diff --git a/packages/api/README.md b/packages/api/README.md
index 30c5f42b7..7de82320a 100644
--- a/packages/api/README.md
+++ b/packages/api/README.md
@@ -106,15 +106,55 @@ HTTP /status
hash: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
timestamp: "2024-06-06T21:50:20.949Z"
}
+ "epoch": {
+ "number": 3640,
+ "firstBlockHeight": 72534,
+ "firstCoreBlockHeight": 1160707,
+ "startTime": 1734457229495,
+ "feeMultiplier": 1,
+ "endTime": 1734460829495
+ },
+ "transactionsCount": 25912,
+ "totalCredits": 7288089799960610,
+ "totalCollectedFeesDay": 12733263640,
+ "transfersCount": 1849,
+ "dataContractsCount": 630,
+ "documentsCount": 15384,
+ "identitiesCount": 712,
+ "network": "dash-testnet-51",
+ "api": {
+ "version": "1.0.7",
+ "block": {
+ "height": 72555,
+ "hash": "EDA1CDF601224CD3ED168D35B4699DE2796F774B526103C64D371EF3AAFD8274",
+ "timestamp": "2024-12-17T17:57:08.758Z"
+ }
+ },
+ "tenderdash": {
+ "version": "1.4.0",
+ "block": {
+ "height": 72555,
+ "hash": "EDA1CDF601224CD3ED168D35B4699DE2796F774B526103C64D371EF3AAFD8274",
+ "timestamp": "2024-12-17T17:57:08.758Z"
+ }
+ },
+ "versions": {
+ "software": {
+ "dapi": "1.5.1",
+ "drive": "1.6.2",
+ "tenderdash": "1.4.0"
},
- tenderdash: {
- version: "0.14.0-dev.6",
- block: {
- height: 20154,
- hash: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
- timestamp: "2024-06-06T21:53:27.947Z"
- }
- }
+ "protocol": {
+ "tenderdash": {
+ "p2p": 10,
+ "block": 14
+ },
+ "drive": {
+ "latest": 6,
+ "current": 6
+ }
+ }
+ }
}
```
---
@@ -762,6 +802,9 @@ GET /identity/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec
"topUpsGasSpent": 46350660,
"withdrawalsGasSpent": 0,
"lastWithdrawalHash": null,
+ "lastWithdrawalTimestamp": null,
+ "totalTopUps": 0,
+ "totalWithdrawals": 0,
"publicKeys": [
{
"keyId": 0,
@@ -1034,8 +1077,9 @@ Response codes:
### Transfers by Identity
Return all transfers made by the given identity
* `limit` cannot be more then 100
+* `type` cannot be less, then 0 and more then 8
```
-GET /identities/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec/transfers?page=1&limit=10&order=asc&type=1
+GET /identities/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec/transfers?hash=445E6F081DEE877867816AD3EF492E2C0BD1DDCCDC9C793B23DDDAF8AEA23118&page=1&limit=10&order=asc&type=6
{
pagination: {
@@ -1052,7 +1096,7 @@ GET /identities/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec/transfers?page=1&li
txHash: "445E6F081DEE877867816AD3EF492E2C0BD1DDCCDC9C793B23DDDAF8AEA23118",
type: 6,
blockHash: "73171E0A8DCC10C6DA501E1C70A9C1E0BD6F1F8F834C2A1E787AF19B1F361D5E"
- }, ...
+ }
]
}
```
diff --git a/packages/api/package.json b/packages/api/package.json
index 8b460ef85..570b94c37 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -12,9 +12,9 @@
"lint": "standard ."
},
"dependencies": {
+ "@dashevo/wasm-dpp": "github:owl352/wasm-dpp",
"@dashevo/dapi-client": "github:owl352/dapi-client",
"@dashevo/dashd-rpc": "19.0.0",
- "@dashevo/wasm-dpp": "github:owl352/wasm-dpp",
"@fastify/cors": "^8.3.0",
"@scure/base": "^1.1.5",
"bs58": "^6.0.0",
diff --git a/packages/api/src/DAPI.js b/packages/api/src/DAPI.js
index 8649b4ad2..db7e425d7 100644
--- a/packages/api/src/DAPI.js
+++ b/packages/api/src/DAPI.js
@@ -106,6 +106,10 @@ class DAPI {
}
})
}
+
+ async getStatus () {
+ return this.dapi.platform.getStatus()
+ }
}
module.exports = DAPI
diff --git a/packages/api/src/controllers/IdentitiesController.js b/packages/api/src/controllers/IdentitiesController.js
index 4644d2807..91c985f8b 100644
--- a/packages/api/src/controllers/IdentitiesController.js
+++ b/packages/api/src/controllers/IdentitiesController.js
@@ -72,9 +72,16 @@ class IdentitiesController {
getTransfersByIdentity = async (request, response) => {
const { identifier } = request.params
- const { page = 1, limit = 10, order = 'asc', type = undefined } = request.query
-
- const transfers = await this.identitiesDAO.getTransfersByIdentity(identifier, Number(page ?? 1), Number(limit ?? 10), order, type)
+ const { page = 1, limit = 10, order = 'asc', type, hash } = request.query
+
+ const transfers = await this.identitiesDAO.getTransfersByIdentity(
+ identifier,
+ hash,
+ Number(page ?? 1),
+ Number(limit ?? 10),
+ order,
+ type
+ )
response.send(transfers)
}
diff --git a/packages/api/src/controllers/MainController.js b/packages/api/src/controllers/MainController.js
index b6a4883cc..ef25c2c46 100644
--- a/packages/api/src/controllers/MainController.js
+++ b/packages/api/src/controllers/MainController.js
@@ -11,20 +11,21 @@ const { base58 } = require('@scure/base')
const API_VERSION = require('../../package.json').version
class MainController {
- constructor (knex, dapi) {
+ constructor (knex, dapi, client) {
this.blocksDAO = new BlocksDAO(knex, dapi)
this.dataContractsDAO = new DataContractsDAO(knex)
this.documentsDAO = new DocumentsDAO(knex)
this.transactionsDAO = new TransactionsDAO(knex, dapi)
- this.identitiesDAO = new IdentitiesDAO(knex, dapi)
+ this.identitiesDAO = new IdentitiesDAO(knex, dapi, client)
this.validatorsDAO = new ValidatorsDAO(knex)
this.dapi = dapi
}
getStatus = async (request, response) => {
- const [blocks, stats, tdStatus, epochsInfo, totalCredits, totalCollectedFeesDay] = (await Promise.allSettled([
+ const [blocks, stats, status, tdStatus, epochsInfo, totalCredits, totalCollectedFeesDay] = (await Promise.allSettled([
this.blocksDAO.getBlocks(1, 1, 'desc'),
this.blocksDAO.getStats(),
+ this.dapi.getStatus(),
TenderdashRPC.getStatus(),
this.dapi.getEpochsInfo(1),
this.dapi.getTotalCredits(),
@@ -56,12 +57,29 @@ class MainController {
}
},
tenderdash: {
- version: tdStatus?.version ?? null,
+ version: status?.version?.software.tenderdash ?? null,
block: {
height: tdStatus?.highestBlock?.height ?? null,
hash: tdStatus?.highestBlock?.hash ?? null,
timestamp: tdStatus?.highestBlock?.timestamp ?? null
}
+ },
+ versions: {
+ software: {
+ dapi: status?.version?.software.dapi ?? null,
+ drive: status?.version?.software.drive ?? null,
+ tenderdash: status?.version?.software.tenderdash ?? null
+ },
+ protocol: {
+ tenderdash: {
+ p2p: status?.version?.protocol.tenderdash?.p2p ?? null,
+ block: status?.version?.protocol.tenderdash?.block ?? null
+ },
+ drive: {
+ latest: status?.version?.protocol.drive?.latest ?? null,
+ current: status?.version?.protocol.drive?.current ?? null
+ }
+ }
}
})
}
diff --git a/packages/api/src/dao/IdentitiesDAO.js b/packages/api/src/dao/IdentitiesDAO.js
index 09e350c81..a06c25ff3 100644
--- a/packages/api/src/dao/IdentitiesDAO.js
+++ b/packages/api/src/dao/IdentitiesDAO.js
@@ -71,6 +71,10 @@ module.exports = class IdentitiesDAO {
.from('with_alias')
.limit(1)
+ const statisticSubquery = this.knex('state_transitions')
+ .whereRaw(`owner = identifier and type=${IDENTITY_CREDIT_WITHDRAWAL}`)
+ .as('statistic')
+
const rows = await this.knex.with('with_alias', mainQuery)
.select(
'identifier', 'owner', 'revision',
@@ -91,13 +95,28 @@ module.exports = class IdentitiesDAO {
.where('owner', identifier)
.andWhere('type', IDENTITY_CREDIT_WITHDRAWAL)
.as('withdrawals_gas_spent'))
- .select(this.knex('state_transitions')
+ .select(this.knex(statisticSubquery)
.select('hash')
- .where('owner', identifier)
- .andWhere('type', IDENTITY_CREDIT_WITHDRAWAL)
+ .where('type', IDENTITY_CREDIT_WITHDRAWAL)
.orderBy('id', 'desc')
.limit(1)
.as('last_withdrawal_hash'))
+ .select(this.knex(statisticSubquery)
+ .select('timestamp')
+ .where('type', IDENTITY_CREDIT_WITHDRAWAL)
+ .orderBy('id', 'desc')
+ .limit(1)
+ .as('last_withdrawal_timestamp'))
+ .select(
+ this.knex(statisticSubquery)
+ .count('id')
+ .whereRaw(`type=${IDENTITY_CREDIT_WITHDRAWAL}`)
+ .as('total_withdrawals'))
+ .select(
+ this.knex(statisticSubquery)
+ .count('id')
+ .whereRaw(`type=${IDENTITY_TOP_UP}`)
+ .as('total_top_ups'))
.from('with_alias')
if (!rows.length) {
@@ -125,7 +144,7 @@ module.exports = class IdentitiesDAO {
if (row.tx_data) {
const { assetLockProof } = await decodeStateTransition(this.client, row.tx_data)
- fundingCoreTx = assetLockProof?.txid
+ fundingCoreTx = assetLockProof?.fundingCoreTx
}
return Identity.fromObject({
@@ -356,24 +375,31 @@ module.exports = class IdentitiesDAO {
return new PaginatedResultSet(rows.map(row => Transaction.fromRow(row)), page, limit, totalCount)
}
- getTransfersByIdentity = async (identifier, page, limit, order, type) => {
+ getTransfersByIdentity = async (identifier, hash, page, limit, order, type) => {
const fromRank = (page - 1) * limit + 1
const toRank = fromRank + limit - 1
+ let searchQuery = `(transfers.sender = '${identifier}' OR transfers.recipient = '${identifier}')`
+
+ if (typeof type === 'number') {
+ searchQuery = searchQuery + ` AND state_transitions.type = ${type}`
+ }
+
+ if (hash) {
+ searchQuery = searchQuery + ` AND state_transitions.hash = '${hash}'`
+ }
+
const subquery = this.knex('transfers')
.select(
'transfers.id as id', 'transfers.amount as amount',
'transfers.sender as sender', 'transfers.recipient as recipient',
'transfers.state_transition_hash as tx_hash',
'state_transitions.block_hash as block_hash',
- 'state_transitions.type as type'
+ 'state_transitions.type as type',
+ 'state_transitions.gas_used as gas_used'
)
.select(this.knex.raw(`rank() over (order by transfers.id ${order}) rank`))
- .whereRaw(`(transfers.sender = '${identifier}' OR transfers.recipient = '${identifier}') ${
- typeof type === 'number'
- ? `AND state_transitions.type = ${type}`
- : ''
- }`)
+ .whereRaw(searchQuery)
.leftJoin('state_transitions', 'state_transitions.hash', 'transfers.state_transition_hash')
const rows = await this.knex.with('with_alias', subquery)
@@ -381,7 +407,7 @@ module.exports = class IdentitiesDAO {
'rank', 'amount', 'block_hash', 'type',
'sender', 'recipient', 'with_alias.id',
'tx_hash', 'blocks.timestamp as timestamp',
- 'block_hash'
+ 'block_hash', 'gas_used'
)
.select(this.knex('with_alias').count('*').as('total_count'))
.leftJoin('blocks', 'blocks.hash', 'with_alias.block_hash')
diff --git a/packages/api/src/models/Identity.js b/packages/api/src/models/Identity.js
index 2e3f1901e..5675a0fa8 100644
--- a/packages/api/src/models/Identity.js
+++ b/packages/api/src/models/Identity.js
@@ -17,6 +17,9 @@ module.exports = class Identity {
lastWithdrawalHash
publicKeys
fundingCoreTx
+ totalTopUps
+ totalWithdrawals
+ lastWithdrawalTimestamp
constructor (
identifier, owner, revision,
@@ -25,7 +28,9 @@ module.exports = class Identity {
totalTransfers, txHash, isSystem,
aliases, totalGasSpent, averageGasSpent,
topUpsGasSpent, withdrawalsGasSpent,
- lastWithdrawalHash, publicKeys, fundingCoreTx
+ lastWithdrawalHash, lastWithdrawalTimestamp,
+ totalTopUps, totalWithdrawals, publicKeys,
+ fundingCoreTx
) {
this.identifier = identifier ? identifier.trim() : null
this.owner = owner ? owner.trim() : null
@@ -46,6 +51,9 @@ module.exports = class Identity {
this.lastWithdrawalHash = lastWithdrawalHash ?? null
this.publicKeys = publicKeys ?? []
this.fundingCoreTx = fundingCoreTx ?? null
+ this.totalTopUps = totalTopUps ?? null
+ this.totalWithdrawals = totalWithdrawals ?? null
+ this.lastWithdrawalTimestamp = lastWithdrawalTimestamp ?? null
}
static fromObject ({
@@ -55,7 +63,8 @@ module.exports = class Identity {
totalTransfers, txHash, isSystem,
aliases, totalGasSpent, averageGasSpent,
topUpsGasSpent, withdrawalsGasSpent,
- lastWithdrawalHash, publicKeys, fundingCoreTx
+ lastWithdrawalHash, publicKeys, fundingCoreTx,
+ totalTopUps, totalWithdrawals, lastWithdrawalTimestamp
}) {
return new Identity(
identifier,
@@ -75,6 +84,9 @@ module.exports = class Identity {
topUpsGasSpent,
withdrawalsGasSpent,
lastWithdrawalHash,
+ lastWithdrawalTimestamp,
+ totalTopUps,
+ totalWithdrawals,
publicKeys,
fundingCoreTx
)
@@ -88,7 +100,8 @@ module.exports = class Identity {
total_transfers, tx_hash, is_system,
aliases, total_gas_spent, average_gas_spent,
top_ups_gas_spent, withdrawals_gas_spent,
- last_withdrawal_hash
+ last_withdrawal_hash, last_withdrawal_timestamp,
+ total_top_ups, total_withdrawals
}) {
return new Identity(
identifier?.trim(),
@@ -107,7 +120,10 @@ module.exports = class Identity {
Number(average_gas_spent),
Number(top_ups_gas_spent),
Number(withdrawals_gas_spent),
- last_withdrawal_hash
+ last_withdrawal_hash,
+ last_withdrawal_timestamp,
+ Number(total_top_ups),
+ Number(total_withdrawals)
)
}
}
diff --git a/packages/api/src/models/Transfer.js b/packages/api/src/models/Transfer.js
index 48c815a9c..f6878c1b5 100644
--- a/packages/api/src/models/Transfer.js
+++ b/packages/api/src/models/Transfer.js
@@ -7,8 +7,9 @@ module.exports = class Transfer {
txHash
type
blockHash
+ gasUsed
- constructor (amount, sender, recipient, timestamp, txHash, type, blockHash) {
+ constructor (amount, sender, recipient, timestamp, txHash, type, blockHash, gasUsed) {
this.amount = amount ?? null
this.sender = sender ? sender.trim() : null
this.recipient = recipient ? recipient.trim() : null
@@ -16,10 +17,11 @@ module.exports = class Transfer {
this.txHash = txHash ?? null
this.type = type ?? null
this.blockHash = blockHash ?? null
+ this.gasUsed = gasUsed ?? null
}
// eslint-disable-next-line camelcase
- static fromRow ({ amount, sender, recipient, timestamp, tx_hash, type, block_hash }) {
- return new Transfer(parseInt(amount), sender, recipient, timestamp, tx_hash, type, block_hash)
+ static fromRow ({ amount, sender, recipient, timestamp, tx_hash, type, block_hash, gas_used }) {
+ return new Transfer(parseInt(amount), sender, recipient, timestamp, tx_hash, type, block_hash, Number(gas_used))
}
}
diff --git a/packages/api/src/schemas.js b/packages/api/src/schemas.js
index 675271b75..e30cdf061 100644
--- a/packages/api/src/schemas.js
+++ b/packages/api/src/schemas.js
@@ -32,6 +32,11 @@ const schemaTypes = [
minimum: 0,
maximum: 8
},
+ hash: {
+ type: 'string',
+ minLength: 64,
+ maxLength: 64
+ },
transaction_type: {
type: ['array', 'null'],
items: {
diff --git a/packages/api/src/server.js b/packages/api/src/server.js
index e5261ba27..9f03e6741 100644
--- a/packages/api/src/server.js
+++ b/packages/api/src/server.js
@@ -76,7 +76,7 @@ module.exports = {
await knex.raw('select 1+1')
- const mainController = new MainController(knex, dapi)
+ const mainController = new MainController(knex, dapi, client)
const epochController = new EpochController(knex, dapi)
const blocksController = new BlocksController(knex, dapi)
const transactionsController = new TransactionsController(client, knex, dapi)
diff --git a/packages/api/src/utils.js b/packages/api/src/utils.js
index 5e70bbc41..dc2aef542 100644
--- a/packages/api/src/utils.js
+++ b/packages/api/src/utils.js
@@ -117,14 +117,12 @@ const decodeStateTransition = async (client, base64) => {
decoded.assetLockProof = {
coreChainLockedHeight: assetLockProof instanceof ChainAssetLockProof ? assetLockProof.getCoreChainLockedHeight() : null,
type: assetLockProof instanceof InstantAssetLockProof ? 'instantSend' : 'chainLock',
- instantLock: assetLockProof instanceof InstantAssetLockProof ? assetLockProof.toJSON().instantLock : null,
+ instantLock: assetLockProof instanceof InstantAssetLockProof ? assetLockProof.getInstantLock().toString('base64') : null,
fundingAmount: decodedTransaction?.outputAmount ?? null,
- txid: Buffer.from(assetLockProof.getOutPoint().slice(0, 32).toReversed()).toString('hex'),
- vout: assetLockProof.getOutPoint().readInt8(32),
- fundingAddress: assetLockProof.getOutput
- ? dashcorelib.Script(assetLockProof.getOutput().script).toAddress(NETWORK).toString()
- : null
+ fundingCoreTx: Buffer.from(assetLockProof.getOutPoint().slice(0, 32).toReversed()).toString('hex'),
+ vout: assetLockProof.getOutPoint().readInt8(32)
}
+
decoded.userFeeIncrease = stateTransition.getUserFeeIncrease()
decoded.identityId = stateTransition.getIdentityId().toString()
decoded.signature = stateTransition.getSignature()?.toString('hex') ?? null
@@ -167,12 +165,10 @@ const decodeStateTransition = async (client, base64) => {
coreChainLockedHeight: assetLockProof instanceof ChainAssetLockProof ? assetLockProof.getCoreChainLockedHeight() : null,
type: assetLockProof instanceof InstantAssetLockProof ? 'instantSend' : 'chainLock',
fundingAmount: decodedTransaction?.outputAmount ?? null,
- txid: Buffer.from(assetLockProof.getOutPoint().slice(0, 32).toReversed()).toString('hex'),
- vout: assetLockProof.getOutPoint().readInt8(32),
- fundingAddress: assetLockProof.getOutput
- ? dashcorelib.Script(assetLockProof.getOutput().script).toAddress(NETWORK).toString()
- : null
+ fundingCoreTx: Buffer.from(assetLockProof.getOutPoint().slice(0, 32).toReversed()).toString('hex'),
+ vout: assetLockProof.getOutPoint().readInt8(32)
}
+
decoded.identityId = stateTransition.getIdentityId().toString()
decoded.amount = output.satoshis * 1000
decoded.signature = stateTransition.getSignature()?.toString('hex') ?? null
@@ -213,7 +209,7 @@ const decodeStateTransition = async (client, base64) => {
decoded.userFeeIncrease = stateTransition.getUserFeeIncrease()
decoded.identityId = stateTransition.getOwnerId().toString()
decoded.revision = stateTransition.getRevision()
- // TODO: Add contract bounds
+
decoded.publicKeysToAdd = stateTransition.getPublicKeysToAdd()
.map(key => {
const { contractBounds } = key.toObject()
@@ -264,7 +260,7 @@ const decodeStateTransition = async (client, base64) => {
break
}
case StateTransitionEnum.IDENTITY_CREDIT_TRANSFER: {
- decoded.identityContractNonce = Number(stateTransition.getIdentityContractNonce())
+ decoded.nonce = Number(stateTransition.getNonce())
decoded.userFeeIncrease = stateTransition.getUserFeeIncrease()
decoded.senderId = stateTransition.getIdentityId().toString()
decoded.recipientId = stateTransition.getRecipientId().toString()
@@ -284,7 +280,6 @@ const decodeStateTransition = async (client, base64) => {
: 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())
@@ -306,6 +301,7 @@ const decodeStateTransition = async (client, base64) => {
decoded.documentTypeName = stateTransition.getContestedDocumentResourceVotePoll().documentTypeName
decoded.indexName = stateTransition.getContestedDocumentResourceVotePoll().indexName
decoded.choice = stateTransition.getContestedDocumentResourceVotePoll().choice
+ decoded.userFeeIncrease = stateTransition.getUserFeeIncrease()
decoded.raw = stateTransition.toBuffer().toString('hex')
decoded.proTxHash = stateTransition.getProTxHash().toString('hex')
diff --git a/packages/api/test/integration/identities.spec.js b/packages/api/test/integration/identities.spec.js
index ab717dea1..0aefd9cdf 100644
--- a/packages/api/test/integration/identities.spec.js
+++ b/packages/api/test/integration/identities.spec.js
@@ -212,7 +212,8 @@ describe('Identities routes', () => {
const { alias } = await fixtures.identity_alias(knex,
{
alias: 'test.dash',
- identity
+ identity,
+ state_transition_hash: transaction.hash
}
)
@@ -242,6 +243,9 @@ describe('Identities routes', () => {
topUpsGasSpent: 0,
withdrawalsGasSpent: 0,
lastWithdrawalHash: null,
+ lastWithdrawalTimestamp: null,
+ totalTopUps: 0,
+ totalWithdrawals: 0,
publicKeys: [],
fundingCoreTx: null
}
@@ -320,7 +324,7 @@ describe('Identities routes', () => {
it('should return identity by dpns', async () => {
const block = await fixtures.block(knex)
const identity = await fixtures.identity(knex, { block_hash: block.hash })
- const { alias } = await fixtures.identity_alias(knex, { alias: 'test-name.1.dash', identity })
+ const { alias } = await fixtures.identity_alias(knex, { alias: 'test-name.1.dash', identity, state_transition_hash: identity.transaction.hash })
const { body } = await client.get('/dpns/identity?dpns=test-name.1.dash')
.expect(200)
@@ -342,7 +346,7 @@ describe('Identities routes', () => {
it('should return identity by dpns with any case', async () => {
const block = await fixtures.block(knex)
const identity = await fixtures.identity(knex, { block_hash: block.hash })
- const { alias } = await fixtures.identity_alias(knex, { alias: 'test-name.2.dash', identity })
+ const { alias } = await fixtures.identity_alias(knex, { alias: 'test-name.2.dash', identity, state_transition_hash: identity.transaction.hash })
const { body } = await client.get('/dpns/identity?dpns=TeSt-NaME.2.DAsH')
.expect(200)
@@ -376,7 +380,7 @@ describe('Identities routes', () => {
for (let i = 0; i < 30; i++) {
block = await fixtures.block(knex, { height: i + 1 })
identity = await fixtures.identity(knex, { block_hash: block.hash })
- alias = await fixtures.identity_alias(knex, { alias: `#test$${i}`, identity })
+ alias = await fixtures.identity_alias(knex, { alias: `#test$${i}`, identity, state_transition_hash: identity.transaction.hash })
identities.push({ identity, block })
aliases.push(alias)
}
@@ -411,7 +415,10 @@ describe('Identities routes', () => {
withdrawalsGasSpent: null,
lastWithdrawalHash: null,
publicKeys: [],
- fundingCoreTx: null
+ fundingCoreTx: null,
+ lastWithdrawalTimestamp: null,
+ totalTopUps: null,
+ totalWithdrawals: null
}))
assert.deepEqual(body.resultSet, expectedIdentities)
@@ -423,7 +430,7 @@ describe('Identities routes', () => {
for (let i = 0; i < 30; i++) {
block = await fixtures.block(knex, { height: i + 1 })
identity = await fixtures.identity(knex, { block_hash: block.hash })
- alias = await fixtures.identity_alias(knex, { alias: `#test1$${i}`, identity })
+ alias = await fixtures.identity_alias(knex, { alias: `#test1$${i}`, identity, state_transition_hash: identity.transaction.hash })
identities.push({ identity, block })
aliases.push(alias)
}
@@ -460,7 +467,10 @@ describe('Identities routes', () => {
withdrawalsGasSpent: null,
lastWithdrawalHash: null,
publicKeys: [],
- fundingCoreTx: null
+ fundingCoreTx: null,
+ lastWithdrawalTimestamp: null,
+ totalTopUps: null,
+ totalWithdrawals: null
}))
assert.deepEqual(body.resultSet, expectedIdentities)
@@ -473,7 +483,7 @@ describe('Identities routes', () => {
for (let i = 0; i < 30; i++) {
block = await fixtures.block(knex, { height: i + 1 })
identity = await fixtures.identity(knex, { block_hash: block.hash })
- alias = await fixtures.identity_alias(knex, { alias: `#test2$${i}`, identity })
+ alias = await fixtures.identity_alias(knex, { alias: `#test2$${i}`, identity, state_transition_hash: identity.transaction.hash })
identities.push({ identity, block })
aliases.push(alias)
}
@@ -510,7 +520,10 @@ describe('Identities routes', () => {
withdrawalsGasSpent: null,
lastWithdrawalHash: null,
publicKeys: [],
- fundingCoreTx: null
+ fundingCoreTx: null,
+ lastWithdrawalTimestamp: null,
+ totalTopUps: null,
+ totalWithdrawals: null
}))
assert.deepEqual(body.resultSet, expectedIdentities)
@@ -523,7 +536,7 @@ describe('Identities routes', () => {
for (let i = 0; i < 30; i++) {
block = await fixtures.block(knex, { height: i + 1 })
identity = await fixtures.identity(knex, { block_hash: block.hash })
- alias = await fixtures.identity_alias(knex, { alias: `#test3$${i}`, identity })
+ alias = await fixtures.identity_alias(knex, { alias: `#test3$${i}`, identity, state_transition_hash: identity.transaction.hash })
identities.push({ identity, block })
aliases.push(alias)
}
@@ -561,7 +574,10 @@ describe('Identities routes', () => {
withdrawalsGasSpent: null,
lastWithdrawalHash: null,
publicKeys: [],
- fundingCoreTx: null
+ fundingCoreTx: null,
+ lastWithdrawalTimestamp: null,
+ totalTopUps: null,
+ totalWithdrawals: null
}))
assert.deepEqual(body.resultSet, expectedIdentities)
@@ -590,7 +606,7 @@ describe('Identities routes', () => {
identity.transactions = transactions
identities.push({ identity, block })
- alias = await fixtures.identity_alias(knex, { alias: `#test3$${i}`, identity })
+ alias = await fixtures.identity_alias(knex, { alias: `#test3$${i}`, identity, state_transition_hash: identity.transaction.hash })
aliases.push(alias)
}
@@ -627,7 +643,10 @@ describe('Identities routes', () => {
withdrawalsGasSpent: null,
lastWithdrawalHash: null,
publicKeys: [],
- fundingCoreTx: null
+ fundingCoreTx: null,
+ lastWithdrawalTimestamp: null,
+ totalTopUps: null,
+ totalWithdrawals: null
}))
assert.deepEqual(body.resultSet, expectedIdentities)
@@ -654,7 +673,7 @@ describe('Identities routes', () => {
identity.balance = transfer.amount
identities.push({ identity, block, transfer })
- alias = await fixtures.identity_alias(knex, { alias: `#test3$${i}`, identity })
+ alias = await fixtures.identity_alias(knex, { alias: `#test3$${i}`, identity, state_transition_hash: identity.transaction.hash })
aliases.push(alias)
}
@@ -705,7 +724,10 @@ describe('Identities routes', () => {
withdrawalsGasSpent: null,
lastWithdrawalHash: null,
publicKeys: [],
- fundingCoreTx: null
+ fundingCoreTx: null,
+ lastWithdrawalTimestamp: null,
+ totalTopUps: null,
+ totalWithdrawals: null
}))
assert.deepEqual(body.resultSet, expectedIdentities)
@@ -1315,7 +1337,8 @@ describe('Identities routes', () => {
transaction = await fixtures.transaction(knex, {
block_hash: block.hash,
owner: identity.identifier,
- type: StateTransitionEnum.IDENTITY_TOP_UP
+ type: StateTransitionEnum.IDENTITY_TOP_UP,
+ gas_used: 123
})
transfer = await fixtures.transfer(knex, {
amount: 1000,
@@ -1345,12 +1368,103 @@ describe('Identities routes', () => {
timestamp: _transfer.block.timestamp.toISOString(),
txHash: _transfer.transfer.state_transition_hash,
type: _transfer.transaction.type,
- blockHash: _transfer.block.hash
+ blockHash: _transfer.block.hash,
+ gasUsed: _transfer.transaction.gas_used
+ }))
+
+ assert.deepEqual(body.resultSet, expectedTransfers)
+ })
+
+ it('should return default set of transfers by identity and type', async () => {
+ block = await fixtures.block(knex, { height: 1 })
+ identity = await fixtures.identity(knex, { block_hash: block.hash })
+ transfers = []
+
+ for (let i = 1; i < 31; i++) {
+ block = await fixtures.block(knex, { height: i + 1 })
+ transaction = await fixtures.transaction(knex, {
+ block_hash: block.hash,
+ owner: identity.identifier,
+ type: i % 2 === 0 ? 5 : 6,
+ gas_used: 123
+ })
+ transfer = await fixtures.transfer(knex, {
+ amount: 1000,
+ recipient: identity.identifier,
+ sender: null,
+ state_transition_hash: transaction.hash
+ })
+ transfers.push({ transfer, transaction, block })
+ }
+
+ const { body } = await client.get(`/identity/${identity.identifier}/transfers?type=5`)
+ .expect(200)
+ .expect('Content-Type', 'application/json; charset=utf-8')
+
+ assert.equal(body.resultSet.length, 10)
+ assert.equal(body.pagination.total, 15)
+ assert.equal(body.pagination.page, 1)
+ assert.equal(body.pagination.limit, 10)
+
+ const expectedTransfers = transfers
+ .filter(_transfer => _transfer.transaction.type === 5)
+ .sort((a, b) => a.block.height - b.block.height)
+ .slice(0, 10)
+ .map((_transfer) => ({
+ amount: parseInt(_transfer.transfer.amount),
+ sender: _transfer.transfer.sender,
+ recipient: _transfer.transfer.recipient,
+ timestamp: _transfer.block.timestamp.toISOString(),
+ txHash: _transfer.transfer.state_transition_hash,
+ type: _transfer.transaction.type,
+ blockHash: _transfer.block.hash,
+ gasUsed: _transfer.transaction.gas_used
}))
assert.deepEqual(body.resultSet, expectedTransfers)
})
+ it('should return transfer by identity and tx hash', async () => {
+ block = await fixtures.block(knex, { height: 1 })
+ identity = await fixtures.identity(knex, { block_hash: block.hash })
+ transfers = []
+
+ transaction = await fixtures.transaction(knex, {
+ block_hash: block.hash,
+ owner: identity.identifier,
+ type: StateTransitionEnum.IDENTITY_TOP_UP,
+ gas_used: 123
+ })
+ transfer = await fixtures.transfer(knex, {
+ amount: 1000,
+ recipient: identity.identifier,
+ sender: null,
+ state_transition_hash: transaction.hash
+ })
+
+ const { body } = await client.get(`/identity/${identity.identifier}/transfers?hash=${transaction.hash}`)
+ .expect(200)
+ .expect('Content-Type', 'application/json; charset=utf-8')
+
+ assert.equal(body.resultSet.length, 1)
+ assert.equal(body.pagination.total, 1)
+ assert.equal(body.pagination.page, 1)
+ assert.equal(body.pagination.limit, 10)
+
+ const expectedTransfers = {
+ amount: transfer.amount,
+ sender: null,
+ recipient: identity.identifier,
+ timestamp: block.timestamp.toISOString(),
+ txHash: transaction.hash,
+ type: transaction.type,
+ blockHash: block.hash,
+ gasUsed: transaction.gas_used
+ }
+
+ assert.deepEqual(body.resultSet, [expectedTransfers])
+ })
+
it('should return default set of transfers by identity desc', async () => {
block = await fixtures.block(knex, { height: 1 })
identity = await fixtures.identity(knex, { block_hash: block.hash })
@@ -1361,7 +1475,8 @@ describe('Identities routes', () => {
transaction = await fixtures.transaction(knex, {
block_hash: block.hash,
owner: identity.identifier,
- type: StateTransitionEnum.IDENTITY_TOP_UP
+ type: StateTransitionEnum.IDENTITY_TOP_UP,
+ gas_used: 12
})
transfer = await fixtures.transfer(knex, {
amount: 1000,
@@ -1391,7 +1506,8 @@ describe('Identities routes', () => {
timestamp: _transfer.block.timestamp.toISOString(),
txHash: _transfer.transfer.state_transition_hash,
type: _transfer.transaction.type,
- blockHash: _transfer.block.hash
+ blockHash: _transfer.block.hash,
+ gasUsed: _transfer.transaction.gas_used
}))
assert.deepEqual(body.resultSet, expectedTransfers)
@@ -1407,7 +1523,8 @@ describe('Identities routes', () => {
transaction = await fixtures.transaction(knex, {
block_hash: block.hash,
owner: identity.identifier,
- type: StateTransitionEnum.IDENTITY_TOP_UP
+ type: StateTransitionEnum.IDENTITY_TOP_UP,
+ gas_used: 22
})
transfer = await fixtures.transfer(knex, {
amount: 1000,
@@ -1437,7 +1554,8 @@ describe('Identities routes', () => {
timestamp: _transfer.block.timestamp.toISOString(),
txHash: _transfer.transfer.state_transition_hash,
type: _transfer.transaction.type,
- blockHash: _transfer.block.hash
+ blockHash: _transfer.block.hash,
+ gasUsed: _transfer.transaction.gas_used
}))
assert.deepEqual(body.resultSet, expectedTransfers)
@@ -1453,7 +1571,8 @@ describe('Identities routes', () => {
transaction = await fixtures.transaction(knex, {
block_hash: block.hash,
owner: identity.identifier,
- type: StateTransitionEnum.IDENTITY_TOP_UP
+ type: StateTransitionEnum.IDENTITY_TOP_UP,
+ gas_used: 33
})
transfer = await fixtures.transfer(knex, {
amount: 1000,
@@ -1483,7 +1602,8 @@ describe('Identities routes', () => {
timestamp: _transfer.block.timestamp.toISOString(),
txHash: _transfer.transfer.state_transition_hash,
type: _transfer.transaction.type,
- blockHash: _transfer.block.hash
+ blockHash: _transfer.block.hash,
+ gasUsed: _transfer.transaction.gas_used
}))
assert.deepEqual(body.resultSet, expectedTransfers)
diff --git a/packages/api/test/integration/main.spec.js b/packages/api/test/integration/main.spec.js
index 81cbc9796..106a07b2b 100644
--- a/packages/api/test/integration/main.spec.js
+++ b/packages/api/test/integration/main.spec.js
@@ -43,6 +43,8 @@ describe('Other routes', () => {
mock.method(DAPI.prototype, 'getIdentityKeys', async () => null)
+ mock.method(DAPI.prototype, 'getStatus', async () => null)
+
mock.method(tenderdashRpc, 'getBlockByHeight', async () => ({
block: {
header: {
@@ -82,7 +84,8 @@ describe('Other routes', () => {
identityAlias = await fixtures.identity_alias(knex, {
alias: 'dpns.dash',
- identity
+ identity,
+ state_transition_hash: identityTransaction.hash
})
dataContractTransaction = await fixtures.transaction(knex, {
@@ -367,7 +370,10 @@ describe('Other routes', () => {
withdrawalsGasSpent: 0,
lastWithdrawalHash: null,
publicKeys: [],
- fundingCoreTx: null
+ fundingCoreTx: null,
+ lastWithdrawalTimestamp: null,
+ totalTopUps: 0,
+ totalWithdrawals: 0
}
assert.deepEqual({ identity: expectedIdentity }, body)
@@ -384,8 +390,29 @@ describe('Other routes', () => {
timestamp: new Date().toISOString()
}
}
+ const mockDapiStatus = {
+ version: {
+ software: {
+ dapi: '1.5.1',
+ drive: '1.6.2',
+ tenderdash: '1.4.0'
+ },
+ protocol: {
+ tenderdash: {
+ p2p: 10,
+ block: 14
+ },
+ drive: {
+ latest: 6,
+ current: 6
+ }
+ }
+ }
+ }
+
mock.reset()
mock.method(DAPI.prototype, 'getTotalCredits', async () => 0)
+ mock.method(DAPI.prototype, 'getStatus', async () => mockDapiStatus)
mock.method(DAPI.prototype, 'getEpochsInfo', async () => [{
number: 0,
firstBlockHeight: 0,
@@ -433,12 +460,29 @@ describe('Other routes', () => {
}
},
tenderdash: {
- version: mockTDStatus?.version ?? null,
+ version: mockDapiStatus.version.software.tenderdash ?? null,
block: {
height: mockTDStatus?.highestBlock?.height,
hash: mockTDStatus?.highestBlock?.hash,
timestamp: mockTDStatus?.highestBlock?.timestamp
}
+ },
+ versions: {
+ software: {
+ dapi: mockDapiStatus.version.software.dapi ?? null,
+ drive: mockDapiStatus.version.software.drive ?? null,
+ tenderdash: mockDapiStatus.version.software.tenderdash ?? null
+ },
+ protocol: {
+ tenderdash: {
+ p2p: mockDapiStatus.version.protocol.tenderdash.p2p ?? null,
+ block: mockDapiStatus.version.protocol.tenderdash.block ?? null
+ },
+ drive: {
+ latest: mockDapiStatus.version.protocol.drive.latest ?? null,
+ current: mockDapiStatus.version.protocol.drive.current ?? null
+ }
+ }
}
}
diff --git a/packages/api/test/integration/transactions.spec.js b/packages/api/test/integration/transactions.spec.js
index 9bcf199d7..9db9b375f 100644
--- a/packages/api/test/integration/transactions.spec.js
+++ b/packages/api/test/integration/transactions.spec.js
@@ -42,7 +42,7 @@ describe('Transaction routes', () => {
})
identity = await fixtures.identity(knex, { block_hash: block.hash })
- identityAlias = await fixtures.identity_alias(knex, { alias: 'test.dash', identity })
+ identityAlias = await fixtures.identity_alias(knex, { alias: 'test.dash', identity, state_transition_hash: identity.transaction.hash })
transactions = [{ transaction: identity.transaction, block }]
diff --git a/packages/api/test/unit/utils.spec.js b/packages/api/test/unit/utils.spec.js
index 02a84ef28..b8597e526 100644
--- a/packages/api/test/unit/utils.spec.js
+++ b/packages/api/test/unit/utils.spec.js
@@ -105,9 +105,8 @@ describe('Utils', () => {
coreChainLockedHeight: null,
type: 'instantSend',
fundingAmount: 34999000,
- txid: 'fc89dd4cbe2518da3cd9737043603e81665df58d4989a38b2942eec56bacad1d',
vout: 0,
- fundingAddress: 'yeMdYXBPum8RmHvrq5SsYE9zNYhMEimbUY',
+ fundingCoreTx: 'fc89dd4cbe2518da3cd9737043603e81665df58d4989a38b2942eec56bacad1d',
instantLock: 'AQEKM9t1ICNzvddKryjM4enKn0Y5amBn3o6DwDoC4uk5SAAAAAAdraxrxe5CKYujiUmN9V1mgT5gQ3Bz2TzaGCW+TN2J/JQP49yOk0uJ6el6ls9CmNo++yPYoX1Sx1lWEZTTAAAAhXiuCBXgzawuboxMAXDiXQpJCCPi417VE4mdcYPgTa0/Hd+RCHLAR6H+MXhqKazlGddI7AdWxxLZ94ZvQu+qIpe7G9XRRjQWeYwroIyc6MqQF5mKpvV0AUMYUNMXjCsq'
},
userFeeIncrease: 65,
@@ -161,9 +160,8 @@ describe('Utils', () => {
coreChainLockedHeight: null,
type: 'instantSend',
fundingAmount: 999000,
- txid: '7734f498c5b59f64f73070e0a5ec4fa113065da00358223cf888c3c27317ea64',
vout: 0,
- fundingAddress: 'yWxCwVRgqRmePNPJxezgus1T7xSv5q17SU'
+ fundingCoreTx: '7734f498c5b59f64f73070e0a5ec4fa113065da00358223cf888c3c27317ea64'
},
identityId: '4EfA9Jrvv3nnCFdSf7fad59851iiTRZ6Wcu6YVJ4iSeF',
amount: 300000000,
@@ -277,7 +275,7 @@ describe('Utils', () => {
assert.deepEqual(decoded, {
type: 7,
- identityContractNonce: 3,
+ nonce: 3,
userFeeIncrease: 2,
senderId: '4CpFVPyU95ZxNeDnRWfkpjUa9J72i3nZ4YPsTnpdUudu',
recipientId: 'GxdRSLivPDeACYU8Z6JSNvtrRPX7QG715JoumnctbwWN',
@@ -295,7 +293,6 @@ describe('Utils', () => {
type: 6,
outputAddress: 'yZF5JqEgS9xT1xSkhhUQACdLLDbqSixL8i',
userFeeIncrease: 2,
- identityContractNonce: 1,
senderId: 'FvqzjDyub72Hk51pcmJvd1JUACuor7vA3aJawiVG7Z17',
amount: 1000000,
identityNonce: 1,
@@ -327,7 +324,8 @@ describe('Utils', () => {
indexName: 'parentNameAndLabel',
choice: 'TowardsIdentity(4VRAaVi8vq492FznoHKTsQd4odaXa7vDxdghpTSQBVSV)',
raw: '0800bc77a5a2cec455c79fb92fb683dbd87a2a92b663c9a46d0c50d11889b4aeb121126fac34e15653f82356cffd3d37c5cd84c1f634d4043340dbae781d93d6b87e000000e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c5315506646f6d61696e12706172656e744e616d65416e644c6162656c02120464617368120874657374303130300033daa5a3e330b61e5a4416ab224f0a45ef4e4cab1357b5f4a86fae9314717a561000411f6c69fa9201b57bb7e7c24b392de9056cce5a66bcf2154d57631419e9c68efa8e4d1ca11e81c35de31dd52321d0fbb25f6ff17f5ff69a9cf47fce54746ee72644',
- proTxHash: 'bc77a5a2cec455c79fb92fb683dbd87a2a92b663c9a46d0c50d11889b4aeb121'
+ proTxHash: 'bc77a5a2cec455c79fb92fb683dbd87a2a92b663c9a46d0c50d11889b4aeb121',
+ userFeeIncrease: 0
})
})
})
diff --git a/packages/api/test/utils/fixtures.js b/packages/api/test/utils/fixtures.js
index c1ebf0da5..e088e5c30 100644
--- a/packages/api/test/utils/fixtures.js
+++ b/packages/api/test/utils/fixtures.js
@@ -84,14 +84,15 @@ const fixtures = {
return { ...row, txHash: state_transition_hash ?? transaction.hash, id: result[0].id, transaction }
},
- identity_alias: async (knex, { alias, identity, block_hash } = {}) => {
+ identity_alias: async (knex, { alias, identity, block_hash, state_transition_hash } = {}) => {
if (!identity) {
identity = this.identity(knex, { block_hash })
}
const row = {
identity_identifier: identity.identifier,
- alias
+ alias,
+ state_transition_hash
}
await knex('identity_aliases').insert(row).returning('id')
diff --git a/packages/frontend/public/images/christmas-hat.svg b/packages/frontend/public/images/christmas-hat.svg
new file mode 100644
index 000000000..65e08852c
--- /dev/null
+++ b/packages/frontend/public/images/christmas-hat.svg
@@ -0,0 +1,15 @@
+
diff --git a/packages/frontend/public/images/grain-texture.jpg b/packages/frontend/public/images/grain-texture.jpg
deleted file mode 100644
index 939e74492..000000000
Binary files a/packages/frontend/public/images/grain-texture.jpg and /dev/null differ
diff --git a/packages/frontend/public/images/grain-texture.png b/packages/frontend/public/images/grain-texture.png
new file mode 100644
index 000000000..f87fd6ca4
Binary files /dev/null and b/packages/frontend/public/images/grain-texture.png differ
diff --git a/packages/frontend/public/images/icons/block-present.svg b/packages/frontend/public/images/icons/block-present.svg
new file mode 100644
index 000000000..a4ae33008
--- /dev/null
+++ b/packages/frontend/public/images/icons/block-present.svg
@@ -0,0 +1,14 @@
+
diff --git a/packages/frontend/src/app/api/content.md b/packages/frontend/src/app/api/content.md
index 7696b75cb..fca956050 100644
--- a/packages/frontend/src/app/api/content.md
+++ b/packages/frontend/src/app/api/content.md
@@ -73,15 +73,55 @@ HTTP /status
hash: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
timestamp: "2024-06-06T21:50:20.949Z"
}
+ "epoch": {
+ "number": 3640,
+ "firstBlockHeight": 72534,
+ "firstCoreBlockHeight": 1160707,
+ "startTime": 1734457229495,
+ "feeMultiplier": 1,
+ "endTime": 1734460829495
+ },
+ "transactionsCount": 25912,
+ "totalCredits": 7288089799960610,
+ "totalCollectedFeesDay": 12733263640,
+ "transfersCount": 1849,
+ "dataContractsCount": 630,
+ "documentsCount": 15384,
+ "identitiesCount": 712,
+ "network": "dash-testnet-51",
+ "api": {
+ "version": "1.0.7",
+ "block": {
+ "height": 72555,
+ "hash": "EDA1CDF601224CD3ED168D35B4699DE2796F774B526103C64D371EF3AAFD8274",
+ "timestamp": "2024-12-17T17:57:08.758Z"
+ }
+ },
+ "tenderdash": {
+ "version": "1.4.0",
+ "block": {
+ "height": 72555,
+ "hash": "EDA1CDF601224CD3ED168D35B4699DE2796F774B526103C64D371EF3AAFD8274",
+ "timestamp": "2024-12-17T17:57:08.758Z"
+ }
+ },
+ "versions": {
+ "software": {
+ "dapi": "1.5.1",
+ "drive": "1.6.2",
+ "tenderdash": "1.4.0"
},
- tenderdash: {
- version: "0.14.0-dev.6",
- block: {
- height: 20154,
- hash: "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
- timestamp: "2024-06-06T21:53:27.947Z"
- }
- }
+ "protocol": {
+ "tenderdash": {
+ "p2p": 10,
+ "block": 14
+ },
+ "drive": {
+ "latest": 6,
+ "current": 6
+ }
+ }
+ }
}
```
---
@@ -707,7 +747,7 @@ Return identity by given identifier
GET /identity/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec
{
- "identifier": "3igSMtXaaS9iRQHbWU1w4hHveKdxixwMpgmhLzjVhFZJ",
+ "identifier": "GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec",
"revision": 0,
"balance": 49989647300,
"timestamp": "2024-10-12T18:51:44.592Z",
@@ -729,6 +769,9 @@ GET /identity/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec
"topUpsGasSpent": 46350660,
"withdrawalsGasSpent": 0,
"lastWithdrawalHash": null,
+ "lastWithdrawalTimestamp": null,
+ "totalTopUps": 0,
+ "totalWithdrawals": 0,
"publicKeys": [
{
"keyId": 0,
@@ -1002,7 +1045,7 @@ Response codes:
Return all transfers made by the given identity
* `limit` cannot be more then 100
```
-GET /identities/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec/transfers?page=1&limit=10&order=asc&type=1
+GET /identities/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec/transfers?hash=445E6F081DEE877867816AD3EF492E2C0BD1DDCCDC9C793B23DDDAF8AEA23118&page=1&limit=10&order=asc&type=6
{
pagination: {
@@ -1019,7 +1062,7 @@ GET /identities/GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec/transfers?page=1&li
txHash: "445E6F081DEE877867816AD3EF492E2C0BD1DDCCDC9C793B23DDDAF8AEA23118",
type: 6,
blockHash: "73171E0A8DCC10C6DA501E1C70A9C1E0BD6F1F8F834C2A1E787AF19B1F361D5E"
- }, ...
+ }
]
}
```
diff --git a/packages/frontend/src/app/block/[hash]/Block.js b/packages/frontend/src/app/block/[hash]/Block.js
index 51f8d8c55..362b86825 100644
--- a/packages/frontend/src/app/block/[hash]/Block.js
+++ b/packages/frontend/src/app/block/[hash]/Block.js
@@ -16,7 +16,6 @@ import {
function Block ({ hash }) {
const [block, setBlock] = useState({ data: {}, loading: true, error: false })
const [rate, setRate] = useState({ data: {}, loading: true, error: false })
- const txHashes = block.data?.txs || []
const tdTitleWidth = 250
const fetchData = () => {
@@ -95,7 +94,7 @@ function Block ({ hash }) {
Transactions count |
- {txHashes?.length}
+ {block.data?.txs?.length}
|
@@ -111,7 +110,7 @@ function Block ({ hash }) {
: }
- {txHashes.length
+ {block.data?.txs?.length
?
Transactions
- ({ hash }))}
- variant={'hashes'}
- rate={rate.data}
- />
+
: null}
diff --git a/packages/frontend/src/app/dataContract/[identifier]/DataContract.js b/packages/frontend/src/app/dataContract/[identifier]/DataContract.js
index 185dd4e55..d2e7db1de 100644
--- a/packages/frontend/src/app/dataContract/[identifier]/DataContract.js
+++ b/packages/frontend/src/app/dataContract/[identifier]/DataContract.js
@@ -125,7 +125,7 @@ function DataContract ({ identifier }) {
{dataContract?.data?.name || ''}
{dataContract.data?.identifier
- ?
+ ?
:
}
diff --git a/packages/frontend/src/app/home/Home.js b/packages/frontend/src/app/home/Home.js
index 449bd8622..19a094762 100644
--- a/packages/frontend/src/app/home/Home.js
+++ b/packages/frontend/src/app/home/Home.js
@@ -83,6 +83,7 @@ function Home () {
documents={status.data?.documentsCount}
identities={status.data?.identitiesCount}
loading={status.loading}
+ event={'christmas'}
/>
diff --git a/packages/frontend/src/app/identity/[identifier]/Identity.js b/packages/frontend/src/app/identity/[identifier]/Identity.js
index bb4e67f1d..7a3f986a4 100644
--- a/packages/frontend/src/app/identity/[identifier]/Identity.js
+++ b/packages/frontend/src/app/identity/[identifier]/Identity.js
@@ -123,7 +123,7 @@ function Identity ({ identifier }) {
{identifier
?
-
+
:
}
diff --git a/packages/frontend/src/app/validator/[hash]/BlocksChart.js b/packages/frontend/src/app/validator/[hash]/BlocksChart.js
index 92dec1585..5124c20ef 100644
--- a/packages/frontend/src/app/validator/[hash]/BlocksChart.js
+++ b/packages/frontend/src/app/validator/[hash]/BlocksChart.js
@@ -1,44 +1,15 @@
-import { useState, useEffect, useRef } from 'react'
-import useResizeObserver from '@react-hook/resize-observer'
-import { fetchHandlerSuccess, fetchHandlerError, getDaysBetweenDates, getDynamicRange } from '../../../util'
-import { LineChart, TimeframeSelector } from './../../../components/charts'
import * as Api from '../../../util/Api'
-import { ErrorMessageBlock } from '../../../components/Errors'
+import { useState, useEffect } from 'react'
+import { fetchHandlerSuccess, fetchHandlerError, getDaysBetweenDates } from '../../../util'
+import TabsChartBlock from '../../../components/charts/TabsChartBlock'
+import { defaultChartConfig } from '../../../components/charts/config'
-const chartConfig = {
- timespan: {
- defaultIndex: 3,
- values: [
- {
- label: '24 hours',
- range: getDynamicRange(24 * 60 * 60 * 1000)
- },
- {
- label: '3 days',
- range: getDynamicRange(3 * 24 * 60 * 60 * 1000)
- },
- {
- label: '1 week',
- range: getDynamicRange(7 * 24 * 60 * 60 * 1000)
- },
- {
- label: '1 Month',
- range: getDynamicRange(30 * 24 * 60 * 60 * 1000)
- }
- ]
- }
-}
-
-export default function BlocksChart ({ hash, isActive }) {
+export default function BlocksChart ({ hash, isActive, loading }) {
const [blocksHistory, setBlocksHistory] = useState({ data: {}, loading: true, error: false })
- const [timespan, setTimespan] = useState(chartConfig.timespan.values[chartConfig.timespan.defaultIndex])
- const [customRange, setCustomRange] = useState({ start: null, end: null })
- const [menuIsOpen, setMenuIsOpen] = useState(false)
- const TimeframeMenuRef = useRef(null)
- const [selectorHeight, setSelectorHeight] = useState(0)
+ const [timespan, setTimespan] = useState(defaultChartConfig.timespan.values[defaultChartConfig.timespan.defaultIndex])
useEffect(() => {
- const { start = null, end = null } = timespan.range
+ const { start = null, end = null } = timespan?.range
if (!start || !end) return
setBlocksHistory(state => ({ ...state, loading: true }))
@@ -46,59 +17,30 @@ export default function BlocksChart ({ hash, isActive }) {
Api.getBlocksStatsByValidator(hash, start, end)
.then(res => fetchHandlerSuccess(setBlocksHistory, { resultSet: res }))
.catch(err => fetchHandlerError(setBlocksHistory, err))
- }, [timespan, customRange])
-
- const updateMenuHeight = () => {
- if (menuIsOpen && TimeframeMenuRef?.current) {
- const element = TimeframeMenuRef.current
- const height = element.getBoundingClientRect().height
- setSelectorHeight(height)
- } else {
- setSelectorHeight(0)
- }
- }
-
- useEffect(updateMenuHeight, [menuIsOpen, TimeframeMenuRef])
-
- useResizeObserver(TimeframeMenuRef, updateMenuHeight)
-
- if (blocksHistory.error || (!blocksHistory.loading && !blocksHistory.data?.resultSet)) {
- return ()
- }
+ }, [timespan, hash])
return (
-
- setCustomRange({ start, end })}
- />
-
- ({
- x: new Date(item.timestamp),
- y: item.data.blocksCount
- })) || []}
- dataLoading={blocksHistory.loading}
- timespan={timespan.range}
- xAxis={{
- type: (() => {
- if (getDaysBetweenDates(timespan.range.start, timespan.range.end) > 7) return { axis: 'date' }
- if (getDaysBetweenDates(timespan.range.start, timespan.range.end) > 3) return { axis: 'date', tooltip: 'datetime' }
- return { axis: 'time' }
- })()
- }}
- yAxis={{
- type: 'number',
- abbreviation: 'blocks'
- }}
- height={'350px'}
- />
-
-
+ ({
+ x: new Date(item.timestamp),
+ y: item.data.blocksCount
+ })) || []}
+ loading={loading || blocksHistory.loading}
+ error={!hash || blocksHistory.error}
+ xAxis={{
+ type: (() => {
+ if (getDaysBetweenDates(timespan.range.start, timespan.range.end) > 7) return { axis: 'date' }
+ if (getDaysBetweenDates(timespan.range.start, timespan.range.end) > 3) return { axis: 'date', tooltip: 'datetime' }
+ return { axis: 'time' }
+ })()
+ }}
+ yAxis={{
+ type: 'number',
+ abbreviation: 'blocks'
+ }}
+ />
)
}
diff --git a/packages/frontend/src/app/validator/[hash]/RewardsChart.js b/packages/frontend/src/app/validator/[hash]/RewardsChart.js
new file mode 100644
index 000000000..13b57b146
--- /dev/null
+++ b/packages/frontend/src/app/validator/[hash]/RewardsChart.js
@@ -0,0 +1,46 @@
+import * as Api from '../../../util/Api'
+import { useState, useEffect } from 'react'
+import { fetchHandlerSuccess, fetchHandlerError, getDaysBetweenDates } from '../../../util'
+import TabsChartBlock from '../../../components/charts/TabsChartBlock'
+import { defaultChartConfig } from '../../../components/charts/config'
+
+export default function RewardsChart ({ hash, isActive, loading }) {
+ const [rewardsHistory, setRewardsHistory] = useState({ data: {}, loading: true, error: false })
+ const [timespan, setTimespan] = useState(defaultChartConfig.timespan.values[defaultChartConfig.timespan.defaultIndex])
+
+ useEffect(() => {
+ const { start = null, end = null } = timespan?.range
+ if (!start || !end) return
+
+ setRewardsHistory(state => ({ ...state, loading: true }))
+
+ Api.getRewardsStatsByValidator(hash, start, end)
+ .then(res => fetchHandlerSuccess(setRewardsHistory, { resultSet: res }))
+ .catch(err => fetchHandlerError(setRewardsHistory, err))
+ }, [timespan, hash])
+
+ return (
+ ({
+ x: new Date(item.timestamp),
+ y: item.data.reward
+ })) || []}
+ loading={loading || rewardsHistory.loading}
+ error={!hash || rewardsHistory.error}
+ xAxis={{
+ type: (() => {
+ if (getDaysBetweenDates(timespan.range.start, timespan.range.end) > 7) return { axis: 'date' }
+ if (getDaysBetweenDates(timespan.range.start, timespan.range.end) > 3) return { axis: 'date', tooltip: 'datetime' }
+ return { axis: 'time' }
+ })()
+ }}
+ yAxis={{
+ type: 'number',
+ abbreviation: 'Credits'
+ }}
+ />
+ )
+}
diff --git a/packages/frontend/src/app/validator/[hash]/Validator.js b/packages/frontend/src/app/validator/[hash]/Validator.js
index 02a1dd965..dd1015235 100644
--- a/packages/frontend/src/app/validator/[hash]/Validator.js
+++ b/packages/frontend/src/app/validator/[hash]/Validator.js
@@ -9,6 +9,7 @@ import { ErrorMessageBlock } from '../../../components/Errors'
import BlocksList from '../../../components/blocks/BlocksList'
import TransactionsList from '../../../components/transactions/TransactionsList'
import BlocksChart from './BlocksChart'
+import RewardsChart from './RewardsChart'
import Link from 'next/link'
import { Identifier, DateBlock, Endpoint, IpAddress, InfoLine, Credits } from '../../../components/data'
import { ValueContainer, PageDataContainer, InfoContainer } from '../../../components/ui/containers'
@@ -412,19 +413,22 @@ function Validator ({ hash }) {
setActiveChartTab(index)} index={activeChartTab}>
Proposed Blocks
- Reward Earned
+ Reward Earned
- Reward Earned
+
diff --git a/packages/frontend/src/components/blocks/BlocksTotal.js b/packages/frontend/src/components/blocks/BlocksTotal.js
index 2d0db4e1b..4f57c62c6 100644
--- a/packages/frontend/src/components/blocks/BlocksTotal.js
+++ b/packages/frontend/src/components/blocks/BlocksTotal.js
@@ -25,6 +25,7 @@ export default function BlocksTotal () {
return (
{
+ if (menuIsOpen && TimeframeMenuRef?.current) {
+ const element = TimeframeMenuRef.current
+ const height = element.getBoundingClientRect().height
+ setSelectorHeight(height)
+ } else {
+ setSelectorHeight(0)
+ }
+ }
+
+ useEffect(updateMenuHeight, [menuIsOpen, TimeframeMenuRef])
+
+ useResizeObserver(TimeframeMenuRef, updateMenuHeight)
+
+ if (error || (!loading && !data)) {
+ return ()
+ }
+
+ return (
+
+ )
+}
diff --git a/packages/frontend/src/styles/components/TabsChart.scss b/packages/frontend/src/components/charts/TabsChartBlock.scss
similarity index 88%
rename from packages/frontend/src/styles/components/TabsChart.scss
rename to packages/frontend/src/components/charts/TabsChartBlock.scss
index 08e9c001e..478f92a23 100644
--- a/packages/frontend/src/styles/components/TabsChart.scss
+++ b/packages/frontend/src/components/charts/TabsChartBlock.scss
@@ -1,4 +1,5 @@
-.TabsChart {
+.TabsChartBlock {
+ container-type: inline-size;
height: 100%;
transition: all .2s;
@@ -20,8 +21,8 @@
top: -36px;
right: 10px;
}
-
- @media screen and (max-width: 555px) {
+
+ @container (max-width: 500px) {
&__Button {
top: 10px;
right: 12px;
diff --git a/packages/frontend/src/components/charts/TimeframeSelector.js b/packages/frontend/src/components/charts/TimeframeSelector.js
index e423a85ab..3bfa4e4a3 100644
--- a/packages/frontend/src/components/charts/TimeframeSelector.js
+++ b/packages/frontend/src/components/charts/TimeframeSelector.js
@@ -1,12 +1,12 @@
import { useState, useEffect } from 'react'
import TimeframeMenu from './TimeframeMenu'
import { Button } from '@chakra-ui/react'
-import { CalendarIcon2, CloseIcon } from '../../components/ui/icons'
+import { CalendarIcon2, CloseIcon } from '../ui/icons'
import './TimeframeSelector.scss'
export default function TimeframeSelector ({
config,
- isActive,
+ menuIsActive,
changeCallback,
openStateCallback,
menuRef,
@@ -22,12 +22,12 @@ export default function TimeframeSelector ({
}
useEffect(() => {
- if (!isActive) setMenuIsOpen(false)
- }, [isActive])
+ if (!menuIsActive) setMenuIsOpen(false)
+ }, [menuIsActive])
useEffect(() => {
if (typeof openStateCallback === 'function') openStateCallback(menuIsOpen)
- }, [menuIsOpen])
+ }, [menuIsOpen, openStateCallback])
return (
diff --git a/packages/frontend/src/components/charts/config.js b/packages/frontend/src/components/charts/config.js
new file mode 100644
index 000000000..18670c7d8
--- /dev/null
+++ b/packages/frontend/src/components/charts/config.js
@@ -0,0 +1,25 @@
+import { getDynamicRange } from '../../util'
+
+export const defaultChartConfig = {
+ timespan: {
+ defaultIndex: 3,
+ values: [
+ {
+ label: '24 hours',
+ range: getDynamicRange(24 * 60 * 60 * 1000)
+ },
+ {
+ label: '3 days',
+ range: getDynamicRange(3 * 24 * 60 * 60 * 1000)
+ },
+ {
+ label: '1 week',
+ range: getDynamicRange(7 * 24 * 60 * 60 * 1000)
+ },
+ {
+ label: '1 Month',
+ range: getDynamicRange(30 * 24 * 60 * 60 * 1000)
+ }
+ ]
+ }
+}
diff --git a/packages/frontend/src/components/charts/index.js b/packages/frontend/src/components/charts/index.js
index b809eb198..5ac19c416 100644
--- a/packages/frontend/src/components/charts/index.js
+++ b/packages/frontend/src/components/charts/index.js
@@ -109,19 +109,18 @@ const LineGraph = ({
const xAxisFormatCode = typeof xAxis.type === 'string' ? xAxis.type : xAxis.type.axis
const [chartWidth, setChartWidth] = useState(0)
const svgRef = useRef(null)
+ const uniqueComponentId = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
- const getFormatByCode = (code) => {
- if (code === 'number') return d3.format(',.0f')
- if (code === 'date') return d3.timeFormat('%B %d')
- if (code === 'datetime') return d3.timeFormat('%B %d, %H:%M')
- if (code === 'time') return d3.timeFormat('%H:%M')
+ const tickFormats = {
+ number: d3.format(',.0f'),
+ date: d3.timeFormat('%B %d'),
+ datetime: d3.timeFormat('%B %d, %H:%M'),
+ time: d3.timeFormat('%H:%M')
}
- const xTickFormat = (() => {
- return getFormatByCode(xAxisFormatCode)
- })()
-
- const y = d3.scaleLinear(d3.extent(data, d => d.y), [height - marginBottom, marginTop])
+ const xTickFormat = tickFormats[xAxisFormatCode]
+ const filteredData = data.filter(d => typeof d.y === 'number' && !isNaN(d.y))
+ const y = d3.scaleLinear(d3.extent(filteredData, d => d.y), [height - marginBottom, marginTop])
const [x, setX] = useState(() => {
if (xAxisFormatCode === 'number') return d3.scaleLinear(d3.extent(data, d => d.x), [marginLeft, width - marginRight])
@@ -168,6 +167,15 @@ const LineGraph = ({
.y0(y(0))
.y1((d) => y(d.y)))
+ const valuesFormat = (value) => {
+ if (typeof value !== 'number' || isNaN(value)) return value
+
+ if (value >= 1e9) return `${(value / 1e9).toFixed(1)}B`
+ if (value >= 1e6) return `${(value / 1e6).toFixed(1)}M`
+ if (value >= 1e3) return `${(value / 1e3).toFixed(1)}k`
+ return value
+ }
+
useEffect(() => {
d3.select(gx.current)
.call((axis) => {
@@ -204,6 +212,7 @@ const LineGraph = ({
.call(d3.axisLeft(y)
.tickSize(0)
.ticks(5)
+ .tickFormat(valuesFormat)
.tickPadding(10)
)
@@ -318,14 +327,14 @@ const LineGraph = ({
const infoLines = []
const xFormatCode = typeof xAxis.type.tooltip === 'string' ? xAxis.type.tooltip : xAxis.type.axis
- const xFormat = getFormatByCode(xFormatCode)
+ const xFormat = tickFormats[xFormatCode]
infoLines.push({
styles: ['inline', 'tiny'],
value: `${xFormat(data[i].x)}: `
}, {
styles: ['inline', 'bold'],
- value: ` ${data[i].y} `
+ value: ` ${new Intl.NumberFormat('fr-FR', { useGrouping: true, grouping: [3], minimumFractionDigits: 0 }).format(data[i].y)} `
}, {
styles: ['inline', 'tiny'],
value: ` ${yAxis.abbreviation}`
@@ -379,7 +388,7 @@ const LineGraph = ({
overflow={'visible'}
viewBox={`0 0 ${width} ${height}`}
>
-
+
@@ -413,11 +422,11 @@ const LineGraph = ({
-
-
-
+
+
+
-
+
-
+
-
+
@@ -441,7 +450,7 @@ const LineGraph = ({
-
+
diff --git a/packages/frontend/src/components/data/Identifier.scss b/packages/frontend/src/components/data/Identifier.scss
index 250ce7b7b..6a50eab67 100644
--- a/packages/frontend/src/components/data/Identifier.scss
+++ b/packages/frontend/src/components/data/Identifier.scss
@@ -35,6 +35,7 @@
}
&__Avatar {
+ @include mixins.AvatarSize;
flex-shrink: 0;
margin-right: 10px;
}
diff --git a/packages/frontend/src/components/imageGenerator/ImageGenerator.scss b/packages/frontend/src/components/imageGenerator/ImageGenerator.scss
new file mode 100644
index 000000000..16a920106
--- /dev/null
+++ b/packages/frontend/src/components/imageGenerator/ImageGenerator.scss
@@ -0,0 +1,22 @@
+.ImageGenerator {
+ position: relative;
+
+ &__Hat {
+ position: absolute;
+ top: 0;
+ left: 50%;
+
+ &--Christmas {
+ background: url('/images/christmas-hat.svg') center no-repeat;
+ background-size: contain;
+ transform: translate(-45%, -35%);
+ width: 100%;
+ height: 48%;
+ }
+ }
+
+ &__Image {
+ width: 100%;
+ height: 100%;
+ }
+}
diff --git a/packages/frontend/src/components/imageGenerator/index.js b/packages/frontend/src/components/imageGenerator/index.js
index b9eccf45f..20eb4b8d8 100644
--- a/packages/frontend/src/components/imageGenerator/index.js
+++ b/packages/frontend/src/components/imageGenerator/index.js
@@ -1,12 +1,24 @@
import Image from 'next/image'
import { minidenticon } from 'minidenticons'
import { useMemo } from 'react'
+import './ImageGenerator.scss'
-export default function ImageGenerator ({ username, saturation, lightness, ...props }) {
+export default function ImageGenerator ({ username, className, hat = null, saturation, lightness, ...props }) {
const svgURI = useMemo(
() => 'data:image/svg+xml;utf8,' + encodeURIComponent(minidenticon(username, saturation, lightness)),
[username, saturation, lightness]
)
- return ()
+ const ImageElement =
+
+ const hatClasses = {
+ christmas: 'ImageGenerator__Hat--Christmas'
+ }
+
+ return (
+
+ {hat && }
+ {ImageElement}
+
+ )
}
diff --git a/packages/frontend/src/components/layout/Background.js b/packages/frontend/src/components/layout/Background.js
index 9f20c5a54..0aa2680fc 100644
--- a/packages/frontend/src/components/layout/Background.js
+++ b/packages/frontend/src/components/layout/Background.js
@@ -1,9 +1,10 @@
'use client'
import { usePathname } from 'next/navigation'
+import Snow from './Snow'
import './Background.scss'
-function Background () {
+function Background ({ snow }) {
const pathname = usePathname()
const showOnRoutes = [
'/',
@@ -17,7 +18,10 @@ function Background () {
const showDecoration = showOnRoutes.includes(pathname)
return (
-
+ <>
+
+ {snow && }
+ >
)
}
diff --git a/packages/frontend/src/components/layout/Background.scss b/packages/frontend/src/components/layout/Background.scss
index ebf9bbd67..494205b87 100644
--- a/packages/frontend/src/components/layout/Background.scss
+++ b/packages/frontend/src/components/layout/Background.scss
@@ -1,8 +1,9 @@
@import '../../styles/variables.scss';
.Background {
- background-color: #0F1315;
+ background-color: #171E21;
overflow: hidden;
+ pointer-events: none;
z-index: -1;
&, &:after {
@@ -15,12 +16,11 @@
&::after {
content: '';
- background-image: url('/images/grain-texture.jpg');
+ background-image: url('/images/grain-texture.png');
background-position: left;
background-repeat: repeat;
opacity: .5;
z-index: -1;
- mix-blend-mode: soft-light;
}
&--Light {
diff --git a/packages/frontend/src/components/layout/RootComponent.js b/packages/frontend/src/components/layout/RootComponent.js
index 7348a4773..e0089e396 100644
--- a/packages/frontend/src/components/layout/RootComponent.js
+++ b/packages/frontend/src/components/layout/RootComponent.js
@@ -16,7 +16,7 @@ export default function RootComponent ({ children }) {
return (
-
+
{children}
diff --git a/packages/frontend/src/components/layout/Snow.js b/packages/frontend/src/components/layout/Snow.js
new file mode 100644
index 000000000..111e33bc5
--- /dev/null
+++ b/packages/frontend/src/components/layout/Snow.js
@@ -0,0 +1,22 @@
+'use client'
+
+import './Snow.scss'
+
+function Snow () {
+ return (
+
+
+ {Array.from({ length: 50 }).map((_, i) => (
+ ❄
+ ))}
+
+
+ {Array.from({ length: 50 }).map((_, i) => (
+ ❄
+ ))}
+
+
+ )
+}
+
+export default Snow
diff --git a/packages/frontend/src/components/layout/Snow.scss b/packages/frontend/src/components/layout/Snow.scss
new file mode 100644
index 000000000..f7e2618c5
--- /dev/null
+++ b/packages/frontend/src/components/layout/Snow.scss
@@ -0,0 +1,80 @@
+.Snow {
+ &__BottomContainer, &__TopContainer {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ overflow: hidden;
+ }
+
+ &__TopContainer {
+ z-index: 9999;
+ }
+
+ &__BottomContainer {
+ z-index: -1;
+ opacity: .3;
+ }
+
+ &__Snowflake {
+ position: absolute;
+ top: -10%;
+ font-size: 1em;
+ color: white;
+ opacity: 0.8;
+ animation: fall linear infinite, drift infinite ease-in-out;
+
+ &:nth-child(odd) {
+ font-size: 1.5em;
+ opacity: 0.9;
+ }
+
+ &:nth-child(even) {
+ font-size: 0.8em;
+ opacity: 0.7;
+ }
+ }
+
+ &__TopContainer & {
+ &__Snowflake {
+ &:nth-child(1) { left: 5%; animation-duration: 10s, 4s; animation-delay: 0s, 1s; }
+ &:nth-child(2) { left: 30%; animation-duration: 12s, 6s; animation-delay: 1s, 0s; }
+ &:nth-child(3) { left: 50%; animation-duration: 8s, 5s; animation-delay: 2s, 2s; }
+ &:nth-child(4) { left: 70%; animation-duration: 14s, 7s; animation-delay: 3s, 1s; }
+ &:nth-child(5) { left: 95%; animation-duration: 10s, 4s; animation-delay: 4s, 3s; }
+ }
+ }
+
+ &__BottomContainer & {
+ &__Snowflake {
+ &:nth-child(1) { left: 2%; animation-duration: 17s, 7s; animation-delay: 1s, 2.5s; }
+ &:nth-child(2) { left: 32%; animation-duration: 13s, 4s; animation-delay: 3s, 3s; }
+ &:nth-child(3) { left: 50%; animation-duration: 15s, 6s; animation-delay: 0s, 0s; }
+ &:nth-child(4) { left: 72%; animation-duration: 17s, 5s; animation-delay: 1s, 2s; }
+ &:nth-child(5) { left: 98%; animation-duration: 20s, 7s; animation-delay: 0s, 1s; }
+ }
+ }
+
+ @keyframes fall {
+ 0% {
+ top: calc(-10px);
+ }
+ 100% {
+ top: calc(100% + 10px);
+ }
+ }
+
+ @keyframes drift {
+ 0% {
+ margin-left: 0;
+ }
+ 50% {
+ margin-left: 40px;
+ }
+ 100% {
+ margin-left: 0;
+ }
+ }
+}
diff --git a/packages/frontend/src/components/layout/footer/LocalTime.js b/packages/frontend/src/components/layout/footer/LocalTime.js
index b3e2308e0..a71fdc511 100644
--- a/packages/frontend/src/components/layout/footer/LocalTime.js
+++ b/packages/frontend/src/components/layout/footer/LocalTime.js
@@ -1,27 +1,32 @@
'use client'
+import { useEffect, useState } from 'react'
import './LocalTime.scss'
function LocalTime ({ className }) {
- const now = new Date()
- const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
+ const [time, setTime] = useState(null)
+ const [date, setDate] = useState(null)
+ const [timeZone, setTimeZone] = useState(null)
- const time = now.toLocaleTimeString('en-US', {
- hour: '2-digit',
- minute: '2-digit'
- })
-
- const date = now.toLocaleDateString('en-US', {
- weekday: 'short',
- day: '2-digit',
- month: 'short'
- })
+ useEffect(() => {
+ const now = new Date()
+ setTime(now.toLocaleTimeString('en-US', {
+ hour: '2-digit',
+ minute: '2-digit'
+ }))
+ setDate(now.toLocaleDateString('en-US', {
+ weekday: 'short',
+ day: '2-digit',
+ month: 'short'
+ }))
+ setTimeZone(Intl.DateTimeFormat().resolvedOptions().timeZone)
+ }, [])
return (
- {time}
- {date}
- ({timeZone})
+ {time && {time}}
+ {date && {date}}
+ {timeZone && ({timeZone})}
)
}
diff --git a/packages/frontend/src/components/networkStatus/NetworkStatus.scss b/packages/frontend/src/components/networkStatus/NetworkStatus.scss
index dd5fd05f4..4c792d9e7 100644
--- a/packages/frontend/src/components/networkStatus/NetworkStatus.scss
+++ b/packages/frontend/src/components/networkStatus/NetworkStatus.scss
@@ -41,7 +41,6 @@
font-weight: bold;
font-family: $font-heading;
letter-spacing: 0.4px;
- text-transform: uppercase;
&, span {
display: flex;
diff --git a/packages/frontend/src/components/networkStatus/index.js b/packages/frontend/src/components/networkStatus/index.js
index 5762cadc6..89f447c45 100644
--- a/packages/frontend/src/components/networkStatus/index.js
+++ b/packages/frontend/src/components/networkStatus/index.js
@@ -60,12 +60,12 @@ function NetworkStatus ({ className }) {
Platform version:
- 1.7.0
+ {status?.data?.versions?.software?.drive !== undefined ? `v${status?.data?.versions?.software?.drive}` : '-'}
Tenderdash version:
- 1.4.0
+ {status?.data?.versions?.software?.tenderdash ? `v${status?.data?.versions?.software?.tenderdash}` : '-'}
diff --git a/packages/frontend/src/components/total/TotalCards.js b/packages/frontend/src/components/total/TotalCards.js
index cfda03461..dcbb04aac 100644
--- a/packages/frontend/src/components/total/TotalCards.js
+++ b/packages/frontend/src/components/total/TotalCards.js
@@ -3,7 +3,7 @@ import ValueBlock from './ValueBlock'
import { Box } from '@chakra-ui/react'
import './TotalCards.scss'
-export default function TotalCards ({ cards, loading = false }) {
+export default function TotalCards ({ cards, event = null, loading = false }) {
return (
{cards.map((card, i) => (
@@ -14,6 +14,7 @@ export default function TotalCards ({ cards, loading = false }) {
value={card.value}
icon={card.icon}
formats={card.format}
+ event={event}
/>
:
}
diff --git a/packages/frontend/src/components/total/TotalInfo.js b/packages/frontend/src/components/total/TotalInfo.js
index 783c4f171..902b7c523 100644
--- a/packages/frontend/src/components/total/TotalInfo.js
+++ b/packages/frontend/src/components/total/TotalInfo.js
@@ -3,10 +3,22 @@ import './TotalInfoItem.scss'
import { Container, Flex } from '@chakra-ui/react'
import Link from 'next/link'
-export default function TotalInfo ({ blocks, transactions, dataContracts, documents, identities, loading }) {
+export default function TotalInfo ({
+ blocks,
+ transactions,
+ dataContracts,
+ documents,
+ identities,
+ loading,
+ event = null
+}) {
+ const eventClasses = {
+ christmas: 'TotalInfo--Christmas'
+ }
+
return (
{
if (format === 'elipsed') return 'ValueBlock__Value--Elipsed'
@@ -9,7 +12,7 @@ export default function ValueBlock ({ title, value, icon, formats = [], classNam
}).join(' ')
return (
-
+
{icon &&
}
diff --git a/packages/frontend/src/components/total/ValueBlock.scss b/packages/frontend/src/components/total/ValueBlock.scss
index 4a07a5426..85934980e 100644
--- a/packages/frontend/src/components/total/ValueBlock.scss
+++ b/packages/frontend/src/components/total/ValueBlock.scss
@@ -2,101 +2,113 @@
@import '../../styles/variables.scss';
.ValueBlock {
- position: relative;
- display: flex;
- align-items: center;
- padding-left: 44px;
+ position: relative;
+ display: flex;
+ align-items: center;
+ padding-left: 44px;
+ &::before {
+ content: '';
+ display: block;
+ position: absolute;
+ left: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 28px;
+ height: 28px;
+ }
+
+ &--Blocks {
&::before {
- content: '';
- display: block;
- position: absolute;
- left: 0;
- top: 50%;
- transform: translateY(-50%);
- width: 28px;
- height: 28px;
+ background: url('/images/icons/block.svg') no-repeat center;
+ background-size: contain;
}
+ }
- &--Blocks {
- &::before {
- background: url("/images/icons/transactions.svg") no-repeat center;
- background-size: contain;
- }
+ &--Transactions {
+ &::before {
+ background: url('/images/icons/transactions.svg') no-repeat center;
+ background-size: contain;
}
+ }
- &--Transactions {
- &::before {
- background: url('/images/icons/block.svg') no-repeat center;
- background-size: contain;
- }
+ &--Timer {
+ &::before {
+ background: url('/images/icons/timer.svg') no-repeat center;
+ background-size: contain;
}
+ }
- &--Timer {
- &::before {
- background: url('/images/icons/timer.svg') no-repeat center;
- background-size: contain;
- }
+ &--Epoch {
+ &::before {
+ background: url('/images/icons/timer.svg') no-repeat center;
+ background-size: contain;
}
+ }
- &--Epoch {
- &::before {
- background: url('/images/icons/timer.svg') no-repeat center;
- background-size: contain;
- }
+ &--Sandglass {
+ &::before {
+ background: url('/images/icons/sandglass.svg') no-repeat center;
+ background-size: contain;
}
+ }
- &--Sandglass {
- &::before {
- background: url('/images/icons/sandglass.svg') no-repeat center;
- background-size: contain;
- }
+ &--Nodes {
+ &::before {
+ background: url('/images/icons/nodes.svg') no-repeat center;
+ background-size: contain;
}
+ }
- &--Nodes {
- &::before {
- background: url('/images/icons/nodes.svg') no-repeat center;
- background-size: contain;
- }
+ &--Coins {
+ &::before {
+ background: url('/images/icons/coins.svg') no-repeat center;
+ background-size: contain;
}
+ }
- &--Coins {
- &::before {
- background: url('/images/icons/coins.svg') no-repeat center;
- background-size: contain;
- }
+ &--StarCheck {
+ &::before {
+ background: url('/images/icons/star-check.svg') no-repeat center;
+ background-size: contain;
}
+ }
- &--StarCheck {
- &::before {
- background: url('/images/icons/star-check.svg') no-repeat center;
- background-size: contain;
- }
+ &--Christmas.ValueBlock {
+ &--Blocks {
+ &::before {
+ background: url('/images/icons/block-present.svg') no-repeat center;
+ background-size: contain;
+ width: 30px;
+ height: 30px;
+ margin: -1px;
+ }
}
+ }
+
+ &__Title {
+ color: var(--chakra-colors-brand-deep);
+ font-size: 1rem;
+ margin-right: 10px;
+ white-space: nowrap;
+ }
- &__Title {
- color: var(--chakra-colors-brand-deep);
- font-size: 1rem;
- margin-right: 10px;
- white-space: nowrap;
+ &__Value {
+ font-size: 1.125rem;
+
+ &--Loading {
+ @include mixins.LoadingLine;
+
+ opacity: .5;
+ border-radius: 5px;
+ animation-delay: 100ms;
}
-
- &__Value {
- font-size: 1.125rem;
-
- &--Loading {
- @include mixins.LoadingLine;
-
- opacity: .5;
- border-radius: 5px;
- animation-delay: 100ms;
- }
-
- &--Elipsed {
- max-width: 100%;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
+
+ &--Elipsed {
+ max-width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
+ }
}
\ No newline at end of file
diff --git a/packages/frontend/src/components/transactions/TransactionsList.js b/packages/frontend/src/components/transactions/TransactionsList.js
index f265b94ef..d886c4828 100644
--- a/packages/frontend/src/components/transactions/TransactionsList.js
+++ b/packages/frontend/src/components/transactions/TransactionsList.js
@@ -4,7 +4,7 @@ import { EmptyListMessage } from '../ui/lists'
import { Grid, GridItem } from '@chakra-ui/react'
import './TransactionsList.scss'
-export default function TransactionsList ({ transactions = [], showMoreLink, variant = 'full', headerStyles = 'default', rate }) {
+export default function TransactionsList ({ transactions = [], showMoreLink, headerStyles = 'default', rate }) {
const headerExtraClass = {
default: '',
light: 'BlocksList__ColumnTitles--Light'
@@ -12,25 +12,23 @@ export default function TransactionsList ({ transactions = [], showMoreLink, var
return (
- {variant === 'full' &&
-
-
- Time
-
-
- Hash
-
-
- Gas used
-
-
- Owner
-
-
- Type
-
-
- }
+
+
+ Time
+
+
+ Hash
+
+
+ Gas used
+
+
+ Owner
+
+
+ Type
+
+
{transactions?.length > 0
? transactions.map((transaction, key) => (
@@ -38,7 +36,6 @@ export default function TransactionsList ({ transactions = [], showMoreLink, var
key={key}
transaction={transaction}
rate={rate}
- variant={variant}
/>
))
: There are no transactions yet.
diff --git a/packages/frontend/src/components/transactions/TransactionsListItem.js b/packages/frontend/src/components/transactions/TransactionsListItem.js
index 25ca4fdf9..41368a783 100644
--- a/packages/frontend/src/components/transactions/TransactionsListItem.js
+++ b/packages/frontend/src/components/transactions/TransactionsListItem.js
@@ -11,26 +11,12 @@ import './TransactionsListItem.scss'
import ImageGenerator from '../imageGenerator'
import { useRouter } from 'next/navigation'
-function TransactionsListItem ({ transaction, rate, variant = 'full' }) {
+function TransactionsListItem ({ transaction, rate }) {
const activeAlias = transaction?.owner?.aliases?.find(alias => alias.status === 'ok')
const router = useRouter()
- if (variant === 'hashes') {
- return (
-
- {transaction?.hash}
-
- )
- }
-
return (
-
+
{transaction?.timestamp
diff --git a/packages/frontend/src/components/transactions/TransactionsListItem.scss b/packages/frontend/src/components/transactions/TransactionsListItem.scss
index 01b39b86f..7a84ffc7c 100644
--- a/packages/frontend/src/components/transactions/TransactionsListItem.scss
+++ b/packages/frontend/src/components/transactions/TransactionsListItem.scss
@@ -79,6 +79,7 @@
.Identifier,
.TransactionsListItem__AliasContainer,
.Identifier__Avatar,
+ img,
a {
display: block !important;
}
diff --git a/packages/frontend/src/components/validators/ValidatorCard.js b/packages/frontend/src/components/validators/ValidatorCard.js
index c5600e227..73f3f1db4 100644
--- a/packages/frontend/src/components/validators/ValidatorCard.js
+++ b/packages/frontend/src/components/validators/ValidatorCard.js
@@ -15,7 +15,9 @@ export default function ValidatorCard ({ validator, rate, className }) {
lightness={50}
saturation={50}
width={88}
- height={88}/>
+ height={88}
+ hat={'christmas'}
+ />
: 'n/a'
}
diff --git a/packages/frontend/src/styles/components/Table.scss b/packages/frontend/src/styles/components/Table.scss
index 46454e2b0..d36a87be9 100644
--- a/packages/frontend/src/styles/components/Table.scss
+++ b/packages/frontend/src/styles/components/Table.scss
@@ -47,6 +47,8 @@
&__Avatar {
margin-left: 8px;
+ width: 32px;
+ height: 32px;
}
&__SortDirection {
diff --git a/packages/frontend/src/styles/mixins.scss b/packages/frontend/src/styles/mixins.scss
index 34cfc3e66..4fc2fa975 100644
--- a/packages/frontend/src/styles/mixins.scss
+++ b/packages/frontend/src/styles/mixins.scss
@@ -1,5 +1,10 @@
@import './variables.scss';
+@mixin AvatarSize() {
+ height: 24px;
+ width: 24px;
+}
+
@mixin DefListItem($clickable: true) {
display: flex;
width: 100%;
@@ -41,9 +46,9 @@
}
&__Avatar {
+ @include AvatarSize;
+ flex-shrink: 0;
margin-right: 12px;
- height: 28px;
- width: 28px;
}
&__NotActiveText {
diff --git a/packages/frontend/src/styles/theme.scss b/packages/frontend/src/styles/theme.scss
index effe112ea..85a986913 100644
--- a/packages/frontend/src/styles/theme.scss
+++ b/packages/frontend/src/styles/theme.scss
@@ -1,6 +1,5 @@
@import 'components/Table.scss';
@import 'components/InfoBlock.scss';
-@import 'components/TabsChart.scss';
@import './variables.scss';
* {
diff --git a/packages/frontend/src/util/Api.js b/packages/frontend/src/util/Api.js
index e76ce3577..9adb02855 100644
--- a/packages/frontend/src/util/Api.js
+++ b/packages/frontend/src/util/Api.js
@@ -119,6 +119,10 @@ const getBlocksStatsByValidator = (proTxHash, start, end) => {
return call(`validator/${proTxHash}/stats?start=${start}&end=${end}`, 'GET')
}
+const getRewardsStatsByValidator = (proTxHash, start, end) => {
+ return call(`validator/${proTxHash}/rewards/stats?start=${start}&end=${end}`, 'GET')
+}
+
const getStatus = () => {
return call('status', 'GET')
}
@@ -159,6 +163,7 @@ export {
getValidatorByProTxHash,
getBlocksByValidator,
getBlocksStatsByValidator,
+ getRewardsStatsByValidator,
getEpoch,
getRate
}
diff --git a/packages/indexer/Cargo.lock b/packages/indexer/Cargo.lock
index 1ab801a20..adb1ea65b 100644
--- a/packages/indexer/Cargo.lock
+++ b/packages/indexer/Cargo.lock
@@ -594,7 +594,7 @@ dependencies = [
[[package]]
name = "dashpay-contract"
-version = "1.5.1"
+version = "1.7.0"
dependencies = [
"platform-value",
"platform-version",
@@ -604,7 +604,7 @@ dependencies = [
[[package]]
name = "data-contracts"
-version = "1.5.1"
+version = "1.7.0"
dependencies = [
"dashpay-contract",
"dpns-contract",
@@ -614,6 +614,7 @@ dependencies = [
"platform-version",
"serde_json",
"thiserror",
+ "wallet-utils-contract",
"withdrawals-contract",
]
@@ -711,7 +712,7 @@ checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
name = "dpns-contract"
-version = "1.5.1"
+version = "1.7.0"
dependencies = [
"platform-value",
"platform-version",
@@ -721,7 +722,7 @@ dependencies = [
[[package]]
name = "dpp"
-version = "1.5.1"
+version = "1.7.0"
dependencies = [
"anyhow",
"async-trait",
@@ -735,7 +736,7 @@ dependencies = [
"env_logger 0.11.5",
"getrandom",
"hex",
- "indexmap 2.6.0",
+ "indexmap 2.7.0",
"integer-encoding",
"itertools",
"json-schema-compatibility-validator",
@@ -867,7 +868,7 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
[[package]]
name = "feature-flags-contract"
-version = "1.5.1"
+version = "1.7.0"
dependencies = [
"platform-value",
"platform-version",
@@ -1063,7 +1064,7 @@ dependencies = [
"futures-sink",
"futures-util",
"http",
- "indexmap 2.6.0",
+ "indexmap 2.7.0",
"slab",
"tokio",
"tokio-util",
@@ -1144,11 +1145,11 @@ dependencies = [
[[package]]
name = "home"
-version = "0.5.9"
+version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
+checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
dependencies = [
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -1305,9 +1306,9 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.6.0"
+version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
+checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
dependencies = [
"equivalent",
"hashbrown 0.15.0",
@@ -1380,7 +1381,7 @@ dependencies = [
[[package]]
name = "json-schema-compatibility-validator"
-version = "1.5.1"
+version = "1.7.0"
dependencies = [
"json-patch",
"once_cell",
@@ -1419,12 +1420,12 @@ checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
[[package]]
name = "libloading"
-version = "0.8.5"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
+checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
- "windows-targets 0.52.6",
+ "windows-targets 0.48.5",
]
[[package]]
@@ -1451,7 +1452,7 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "masternode-reward-shares-contract"
-version = "1.5.1"
+version = "1.7.0"
dependencies = [
"platform-value",
"platform-version",
@@ -1750,7 +1751,7 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "platform-serialization"
-version = "1.5.1"
+version = "1.7.0"
dependencies = [
"bincode",
"platform-version",
@@ -1758,7 +1759,7 @@ dependencies = [
[[package]]
name = "platform-serialization-derive"
-version = "1.5.1"
+version = "1.7.0"
dependencies = [
"proc-macro2",
"quote",
@@ -1768,13 +1769,13 @@ dependencies = [
[[package]]
name = "platform-value"
-version = "1.5.1"
+version = "1.7.0"
dependencies = [
"base64 0.22.1",
"bincode",
"bs58",
"hex",
- "indexmap 2.6.0",
+ "indexmap 2.7.0",
"lazy_static",
"platform-serialization",
"platform-version",
@@ -1787,7 +1788,7 @@ dependencies = [
[[package]]
name = "platform-version"
-version = "1.5.1"
+version = "1.7.0"
dependencies = [
"bincode",
"grovedb-version",
@@ -1798,7 +1799,7 @@ dependencies = [
[[package]]
name = "platform-versioning"
-version = "1.5.1"
+version = "1.7.0"
dependencies = [
"proc-macro2",
"quote",
@@ -2321,9 +2322,9 @@ dependencies = [
[[package]]
name = "semver"
-version = "1.0.23"
+version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
[[package]]
name = "serde"
@@ -2351,7 +2352,7 @@ version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
dependencies = [
- "indexmap 2.6.0",
+ "indexmap 2.7.0",
"itoa",
"memchr",
"ryu",
@@ -2824,7 +2825,7 @@ version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
- "indexmap 2.6.0",
+ "indexmap 2.7.0",
"toml_datetime",
"winnow 0.5.40",
]
@@ -2835,7 +2836,7 @@ version = "0.22.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
dependencies = [
- "indexmap 2.6.0",
+ "indexmap 2.7.0",
"serde",
"serde_spanned",
"toml_datetime",
@@ -2986,6 +2987,16 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "wallet-utils-contract"
+version = "1.7.0"
+dependencies = [
+ "platform-value",
+ "platform-version",
+ "serde_json",
+ "thiserror",
+]
+
[[package]]
name = "want"
version = "0.3.1"
@@ -3303,7 +3314,7 @@ dependencies = [
[[package]]
name = "withdrawals-contract"
-version = "1.5.1"
+version = "1.7.0"
dependencies = [
"num_enum 0.5.11",
"platform-value",
diff --git a/packages/indexer/Dockerfile b/packages/indexer/Dockerfile
index 9c2e761ee..f7c39a6e0 100644
--- a/packages/indexer/Dockerfile
+++ b/packages/indexer/Dockerfile
@@ -2,7 +2,7 @@ FROM rust:1.82-alpine3.19 as build
RUN apk add --no-cache git cmake clang openssl openssl-dev openssl-libs-static build-base
WORKDIR /
-RUN git clone --depth 1 --branch v1.5.1 https://github.com/dashevo/platform
+RUN git clone --depth 1 --branch v1.7.0 https://github.com/dashevo/platform
WORKDIR /app
COPY Cargo.lock /app
COPY Cargo.toml /app
diff --git a/packages/indexer/migrations/V43__add_identity_alias_st_hash.sql b/packages/indexer/migrations/V43__add_identity_alias_st_hash.sql
new file mode 100644
index 000000000..608ca4e6a
--- /dev/null
+++ b/packages/indexer/migrations/V43__add_identity_alias_st_hash.sql
@@ -0,0 +1,2 @@
+ALTER TABLE identity_aliases
+ADD COLUMN "state_transition_hash" CHAR(64) NOT NULL;
diff --git a/packages/indexer/src/entities/data_contract.rs b/packages/indexer/src/entities/data_contract.rs
index 69ffe6f66..b125ceacd 100644
--- a/packages/indexer/src/entities/data_contract.rs
+++ b/packages/indexer/src/entities/data_contract.rs
@@ -92,7 +92,8 @@ impl From for DataContract {
SystemDataContract::MasternodeRewards => "MasternodeRewards",
SystemDataContract::FeatureFlags => "FeatureFlags",
SystemDataContract::DPNS => "DPNS",
- SystemDataContract::Dashpay => "Dashpay"
+ SystemDataContract::Dashpay => "Dashpay",
+ SystemDataContract::WalletUtils => "WalletUtils"
};
let identifier = data_contract.id();
let source = data_contract.source(platform_version).unwrap();
diff --git a/packages/indexer/src/entities/identity.rs b/packages/indexer/src/entities/identity.rs
index b69a6cb91..c09e9dc63 100644
--- a/packages/indexer/src/entities/identity.rs
+++ b/packages/indexer/src/entities/identity.rs
@@ -2,8 +2,8 @@ use std::env;
use base64::Engine;
use base64::engine::general_purpose;
use dashcore_rpc::{Auth, Client, RpcApi};
+use dashcore_rpc::dashcore::Txid;
use data_contracts::SystemDataContract;
-use dpp::dashcore::{Transaction, Txid};
use dpp::identifier::Identifier;
use dpp::identity::state_transition::AssetLockProved;
use dpp::platform_value::string_encoding::Encoding::{Base58, Base64};
@@ -30,7 +30,7 @@ impl From for Identity {
let asset_lock = state_transition.asset_lock_proof().clone();
let asset_lock_output_index = asset_lock.output_index();
- let transaction: Transaction = match asset_lock {
+ let transaction = match asset_lock {
AssetLockProof::Instant(instant_lock) => instant_lock.transaction,
AssetLockProof::Chain(chain_lock) => {
let tx_hash = chain_lock.out_point.txid.to_string();
diff --git a/packages/indexer/src/processor/psql/dao/mod.rs b/packages/indexer/src/processor/psql/dao/mod.rs
index 6366ad66f..792b05a4c 100644
--- a/packages/indexer/src/processor/psql/dao/mod.rs
+++ b/packages/indexer/src/processor/psql/dao/mod.rs
@@ -179,19 +179,20 @@ impl PostgresDAO {
Ok(())
}
- pub async fn create_identity_alias(&self, identity: Identity, alias: String) -> Result<(), PoolError> {
+ pub async fn create_identity_alias(&self, identity: Identity, alias: String, st_hash: String) -> Result<(), PoolError> {
let client = self.connection_pool.get().await.unwrap();
- let query = "INSERT INTO identity_aliases(identity_identifier,alias) VALUES ($1, $2);";
+ let query = "INSERT INTO identity_aliases(identity_identifier,alias,state_transition_hash) VALUES ($1, $2, $3);";
let stmt = client.prepare_cached(query).await.unwrap();
client.query(&stmt, &[
&identity.identifier.to_string(Base58),
&alias,
+ &st_hash,
]).await.unwrap();
- println!("Created Identity Alias {} -> {}", identity.identifier.to_string(Base58), alias);
+ println!("Created Identity Alias {} -> {} ({})", identity.identifier.to_string(Base58), alias, &st_hash);
Ok(())
}
diff --git a/packages/indexer/src/processor/psql/mod.rs b/packages/indexer/src/processor/psql/mod.rs
index c828b5844..940609e72 100644
--- a/packages/indexer/src/processor/psql/mod.rs
+++ b/packages/indexer/src/processor/psql/mod.rs
@@ -145,7 +145,7 @@ impl PSQLProcessor {
let identity = self.dao.get_identity_by_identifier(identity_identifier.clone()).await.unwrap().expect(&format!("Could not find identity with identifier {}", identity_identifier));
let alias = format!("{}.{}", label, normalized_parent_domain_name);
- self.dao.create_identity_alias(identity, alias).await.unwrap();
+ self.dao.create_identity_alias(identity, alias, st_hash.clone()).await.unwrap();
}
if document_type == "dataContracts" && document_transition.data_contract_id() == self.platform_explorer_identifier {
@@ -431,6 +431,7 @@ impl PSQLProcessor {
self.dao.create_document(dash_tld_document, None).await.unwrap();
}
SystemDataContract::Dashpay => {}
+ SystemDataContract::WalletUtils => {}
}
}
|