Skip to content

[explorer] feat: add NEM account harvest history endpoint - #2584

Open
cryptoBeliever wants to merge 3 commits into
devfrom
explorer/backend/account-harvests
Open

cryptoBeliever wants to merge 3 commits into
devfrom
explorer/backend/account-harvests

Conversation

@cryptoBeliever

Copy link
Copy Markdown
Contributor

Problem

The account page has no way to list the blocks an account harvested.
Adding an address filter to /blocks would have been cheaper, but it would
not carry over to Symbol, where the per-account share lives in the harvestFee
receipts rather than on the block row. That would have locked the frontend
contract to the NEM data model.

Solution

A dedicated endpoint whose response shape is chain independent, so a Symbol
implementation can later serve the same contract from receipts:

GET /api/nem/account/harvests?address=&limit=&offset=&sort=&rewardedOnly=
[{ "height": 1, "timestamp": "2015-03-29 00:06:25", "amount": 102.0, "type": "harvesting" }]
parameter default notes
address required; 400 on a missing or malformed address
limit 10 1–250, shared pagination validation
offset 0
sort DESC
rewardedOnly false drops blocks that paid the harvester nothing

An account with no harvests returns an empty list.
rewardedOnly defaults to false so the endpoint stays
truthful - leaving rows out is an opt-in decision for the caller.

Blocks are matched on beneficiary, not on signer

A delegated harvester signs with its remote account, while the fees - and the
harvested_fees, harvested_blocks and last_harvested_height counters the
puller keeps on accounts - always go to the beneficiary. Matching on the
signer would leave a delegating account with an empty list next to a non-zero
harvested block count for the same account.

NEM has no inflation or block subsidy, so the block fee is the whole reward.

Problem:
The account page has no way to list the blocks an account harvested.
An `address` filter on /blocks would have been cheaper but would not
carry over: in Symbol the per-account reward lives in the harvestFee
receipts, not on the block row, so the frontend contract would have been
locked to the NEM data model.

Solution:
A chain independent endpoint the Symbol implementation can later serve
from receipts:

   GET /api/nem/account/harvests?address=&limit=&offset=&sort=
   [{ "height": 1, "timestamp": "...", "amount": 102.0, "type": "harvesting" }]

`address` is required; an account with no harvests returns an empty list
rather than 404, like the other NEM listings.

Blocks are matched on `beneficiary`, not on `signer`. A delegated
harvester signs with its remote account, while the fees and the harvest
counters the puller keeps on `accounts` always go to the beneficiary.
Problem:
The account page has no way to list the blocks an account harvested.
An `address` filter on /blocks would have been cheaper but would not
carry over: in Symbol the per-account reward lives in the harvestFee
receipts, not on the block row, so the frontend contract would have been
locked to the NEM data model.

Solution:
A chain independent endpoint the Symbol implementation can later serve
from receipts:

   GET /api/nem/account/harvests?address=&limit=&offset=&sort=
   [{ "height": 1, "timestamp": "...", "amount": 102.0, "type": "harvesting" }]

`address` is required; an account with no harvests returns an empty list
rather than 404, like the other NEM listings.

Blocks are matched on `beneficiary`, not on `signer`. A delegated
harvester signs with its remote account, while the fees and the harvest
counters the puller keeps on `accounts` always go to the beneficiary.
Problem:
The account page has no way to list the blocks an account harvested.
An `address` filter on /blocks would have been cheaper but would not
carry over: in Symbol the per-account reward lives in the harvestFee
receipts, not on the block row, so the frontend contract would have been
locked to the NEM data model.

Solution:
A chain independent endpoint the Symbol implementation can later serve
from receipts:

   GET /api/nem/account/harvests?address=&limit=&offset=&sort=
   [{ "height": 1, "timestamp": "...", "amount": 102.0, "type": "harvesting" }]

`address` is required; an account with no harvests returns an empty list
rather than 404, like the other NEM listings.

Blocks are matched on `beneficiary`, not on `signer`. A delegated
harvester signs with its remote account, while the fees and the harvest
counters the puller keeps on `accounts` always go to the beneficiary.
@cryptoBeliever
cryptoBeliever force-pushed the explorer/backend/account-harvests branch from e154146 to 4c0e13d Compare September 18, 2026 15:50

@AnthonyLaw AnthonyLaw left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look good 👍🏼

@Wayonb Wayonb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏾


# endregion


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add testing for invalid values for limit, offset, and sort?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants