Transaction History
Every buy and sell against a bonding curve is an on-chain contract call, indexed by Superhero and served through one endpoint with two filters. Use it to check your own fills, research a token before you buy it, or watch a specific account.
From the command line
node scripts/superhero-transactions.mjs mine [limit] [page]
node scripts/superhero-transactions.mjs token ct_<sale_address> [limit] [page]
node scripts/superhero-transactions.mjs account ak_<address> [limit] [page]
node scripts/superhero-transactions.mjs all [limit] [page]
node scripts/superhero-transactions.mjs activity ct_<sale_address> ak_<address> [limit]| Command | Filter applied | Use it for |
|---|---|---|
mine | your account | Confirming your own entry price and fills |
token | one sale address | Pre-trade research: is the flow organic? |
account | one account | Following a known trader or whale |
all | none | Market pulse: what is being traded right now |
activity | token and account | Checking whether a specific whale is accumulating a specific token |
Default limit is 20 and default page is 1 everywhere. mine needs AE_PRIVATE_KEY set, because
it derives your address from the key; the other four take an address as an argument and need no key.
The API
All five commands are the same endpoint with different query parameters:
GET /api/transactions
?token_address=ct_... sale address of the token
&account_address=ak_... the trader
&includes=token embed the full token record in each row
&limit=20
&page=1Both filters are optional and combine. Omitting both gives you the market-wide feed. The response is
paginated with items and meta.
A single transaction can be fetched by hash:
GET /api/transactions/by-hash?tx_hash=th_...Fields
Each row carries these fields:
| Field | Type | Meaning |
|---|---|---|
tx_hash | string | On-chain transaction hash, and the row's primary key |
sale_address | string | The bonding-curve sale contract the trade hit |
tx_type | string | buy, sell or create_community, nothing else |
block_height | number | Key-block height of inclusion |
address | string | The trader's address |
verified | bool | Whether the indexer has re-validated the row against the chain |
volume | numeric string | Tokens bought or sold, in whole tokens |
protocol_reward | numeric string | ProtocolDAO tokens minted to the buyer, in whole tokens. 0 on a sell |
amount | price object | AE paid or received |
unit_price | price object | amount / volume, the average price you actually got |
previous_buy_price | price object | Unit price before this trade |
buy_price | price object | Unit price after this trade |
sell_price | price object | Legacy field; do not rely on it |
total_supply | numeric string | Token supply after this trade, in whole tokens |
market_cap | price object | buy_price × total_supply at the time of the trade |
created_at | timestamp | Block time |
Every "price object" has ae, usd, eur, aud, brl, cad, chf, gbp and xau keys, so you
can read a trade in any of them without doing your own conversion. Read amount.ae, not amount.
token.* fields are present only when the request carries includes=token or an account_address
filter; otherwise they are absent.
volume is a token count
volume is the number of tokens; amount is the AE. The indexer decodes them from different
events:
| Row field | Decoded from | Units |
|---|---|---|
volume on a buy | the community token's Mint event amount | whole tokens |
volume on a sell | the token's Burn event amount | whole tokens |
amount on a buy | Buy(total_price, …) on the sale contract | AE |
amount on a sell | Sell(return, …) on the sale contract | AE |
protocol_reward | the ProtocolDAO token's Mint event amount | whole tokens |
total_supply | the Buy/Sell event's supply argument, adjusted by volume | whole tokens |
amount on a buy is the fee-inclusive total. Buy's first argument is total_price, which
already contains the 0.5% affiliation fee, and that is why it is the right basis for a PnL cost
figure. The event's own total_supply is the supply before the trade, so the indexer adds
volume on a buy and subtracts it on a sell to store the supply after.
create_community rows are buys
A token creation with an initial buy is stored as one row with tx_type: 'create_community', priced
exactly like a buy. Anything counting purchases must include it; the backend's own PnL queries
count tx_type IN ('buy', 'create_community'). A creation with no initial buy emits no
PriceChange event and is stored with zeroes.
The unfiltered feed is scoped to the current factory: with no token_address, tokens from a
superseded factory deployment do not appear.
What the CLI prints
The transactions script reduces each row to:
function formatTx(tx) {
return {
type: tx.tx_type,
hash: tx.tx_hash,
account: tx.address,
token_name: tx.token?.name,
token_symbol: tx.token?.symbol,
sale_address: tx.sale_address || tx.token?.sale_address,
amount_ae: tx.amount?.ae,
unit_price_ae: tx.unit_price?.ae,
buy_price_ae: tx.buy_price?.ae,
sell_price_ae: tx.sell_price?.ae,
timestamp: tx.created_at,
block_height: tx.block_height,
};
}Pre-trade research
node scripts/superhero-transactions.mjs token ct_<sale_address> 30Many small buyers suggests organic momentum; one large buyer suggests a pump with higher exit risk. On a bonding curve this distinction is sharper than on an order book: a single large buy permanently moves the price for everyone, because the supply genuinely increased. The elevated price sits there until someone sells, whether or not anyone else wanted the token at that level. A chart that has gapped up on one transaction is telling you about one person's position, not about demand.
Three things to count in the output:
- Distinct accounts. Thirty trades from four addresses is four opinions, not thirty.
- Buy-to-sell ratio. A wall of buys with no sells can mean conviction, or it can mean nobody has been able to exit yet.
- Clustering in time. Trades evenly spread over days look different from trades in one minute, and the second pattern often has one account behind it.
Cross-check whatever you conclude against the holders tab. See Reading a Token Page.
Verifying a transaction on-chain
Every row carries a tx_hash. Superhero's indexer is convenient but it is not the chain; to verify a
trade independently, open the hash in aeScan (opens in a new tab). What to check:
- The contract called is the sale address you expected.
- The caller is the account the indexer attributed it to.
- The amount attached matches the AE you think moved.
- The events (
BuyorSellon the sale contract,MintorBurnon the token contract) carry the executed figures, which is what you want if a quote and a fill disagreed.
The same applies to a contract address: paste a sale_address into the explorer and you can read the
deployed code and call its read-only entrypoints directly.
Diagnosing a failed trade
GET /api/debug/failed-transactions is a diagnostic endpoint with no UI behind it. It takes no
parameters, is not scoped to an account, and returns at most 500 rows, newest first:
| Field | Meaning |
|---|---|
hash | The transaction hash the indexer could not process |
retries | How many times it has been retried |
error | The error message |
error_trace | The stack trace |
created_at | When it first failed |
These are transactions the indexer failed to ingest, not transactions that failed on-chain. A
reverted buy never reaches it. A retry job runs every 30 minutes and drops a row once it succeeds or
once retries passes 10, so the table is a rolling backlog rather than a history. If your trade is
on aeScan but missing from /api/transactions, this is where to look for it.
First steps when a trade did not go through:
| Symptom | Abort reason to look for | Likely cause |
|---|---|---|
| Sell reverted, tokens still held | MINIMAL_RETURN_NOT_MEET | The curve moved below your floor |
| Sell reverted, tokens still held | None | No allowance granted to the sale contract |
| Buy reverted | AE_AMOUNT_NOT_SUFFICIENT | Attached AE below price(count) after the curve moved; tolerance too tight |
| Buy or sell reverted | MINIMUM_TOKENS_REQUIRED | count below 10^12, almost always whole tokens passed where decimal units were expected |
| Nothing in your transaction list, nothing on-chain | None | The transaction was never signed or never broadcast. Check the wallet |
| On-chain but not in the list | None | Indexer lag, or an ingest failure. Check /api/debug/failed-transactions |
See Buying & Selling for the allowance and slippage mechanics behind the first two rows.
Related
- Reading a Token Page: the holders and chart panels to weigh this data against
- Buying & Selling: what each of these transactions did on-chain
- Portfolio & PnL: your positions, which these fills add up to
- The Trending Score: the momentum signal that trade flow either confirms or contradicts
- Transactions API: the endpoint reference
- aeScan (opens in a new tab): the æternity explorer for verifying any hash or address