The frontend tile history feature is complete and currently uses mock data in development. To display real blockchain data, the following API endpoints need to be implemented in the backend.
Returns complete history for a specific tile.
Response Structure:
{
"tile_id": 1234,
"purchases": [...],
"transfers": [...],
"changes": [...],
"wrapped_events": [...]
}Returns all purchase/sale events for a tile.
Response Structure:
{
"purchases": [
{
"id": 1,
"timestamp": "2023-01-15T10:30:00Z",
"block_number": 16400000,
"tx": "0xabc123...",
"log_index": 45,
"sold_by": "0x1234...",
"sold_by_ens": "seller.eth",
"purchased_by": "0x5678...",
"purchased_by_ens": "buyer.eth",
"price": "5000000000000000000", // Wei
"eth_price_usd": 1500.50, // ETH price at time of sale
"sale_price_usd": 7502.50
}
]
}Returns all transfer events (including wrapping/unwrapping).
Response Structure:
{
"transfers": [
{
"id": 1,
"timestamp": "2023-01-15T10:30:00Z",
"block_number": 16400000,
"tx": "0xabc123...",
"log_index": 45,
"from": "0x1234...",
"from_ens": "sender.eth",
"to": "0x5678...",
"to_ens": "receiver.eth",
"transfer_type": "transfer", // "wrap", "unwrap", "transfer", "gift"
"is_wrapper_contract": false
}
]
}Returns all data changes (image, URL, price updates).
Response Structure:
{
"changes": [
{
"id": 1,
"timestamp": "2023-01-15T10:30:00Z",
"block_number": 16400000,
"tx": "0xabc123...",
"log_index": 45,
"change_type": "image", // "image", "url", "price", "multiple"
"previous_image": "FF0FF0...", // If image change
"new_image": "00F00F...",
"previous_url": "https://old.com", // If URL change
"new_url": "https://new.com",
"previous_price": "1000000000000000000", // If price change
"new_price": "2000000000000000000",
"updated_by": "0x1234...",
"updated_by_ens": "updater.eth"
}
]
}Returns wrapping/unwrapping history.
Response Structure:
{
"wrapping_events": [
{
"id": 1,
"timestamp": "2023-01-15T10:30:00Z",
"block_number": 16400000,
"tx": "0xabc123...",
"log_index": 45,
"wrapped": true, // true for wrap, false for unwrap
"updated_by": "0x1234...",
"updated_by_ens": "wrapper.eth"
}
]
}The backend already has these tables that can be queried:
-
purchase_histories
- tile_id, sold_by, purchased_by, price, tx, timestamp, block_number, log_index
-
transfer_histories
- tile_id, transferred_from, transferred_to, tx, timestamp, block_number, log_index
-
data_histories
- tile_id, image, url, price, updated_by, tx, timestamp, block_number, log_index
-
wrapping_histories
- tile_id, wrapped, updated_by, tx, timestamp, block_number, log_index
Example for purchase history:
SELECT
ph.*,
ens_from.name as sold_by_ens,
ens_to.name as purchased_by_ens
FROM purchase_histories ph
LEFT JOIN ens_lookup ens_from ON ph.sold_by = ens_from.address
LEFT JOIN ens_lookup ens_to ON ph.purchased_by = ens_to.address
WHERE ph.tile_id = $1
ORDER BY ph.timestamp DESC, ph.log_index DESC;The PixelMap wrapper contract address is: 0x2A46f3e77E2d9BFF52b83B7aDD41081Ab2c6Aaac
When detecting wrap/unwrap events:
- Wrap: transfer TO the wrapper contract
- Unwrap: transfer FROM the wrapper contract
ENS names should be resolved and cached for better UX. Consider implementing a batch ENS resolver to handle multiple addresses efficiently.
Consider integrating with a price oracle API (like CoinGecko or Chainlink) to get historical ETH prices for showing USD values at the time of transactions.
The frontend is already set up to consume these endpoints. Once implemented, update:
- Remove mock data usage by setting
NEXT_PUBLIC_USE_MOCK_HISTORY=false - Update
fetchTileHistoryinutils/tileHistory.tsto call the real endpoints - The TileHistory component will automatically use the real data
High priority endpoints (implement first):
/api/tile/{id}/purchases- Most important for users/api/tile/{id}/changes- Shows tile evolution/api/tile/{id}/transfers- Shows ownership changes
Medium priority:
4. /api/tile/{id}/wrapping - Important for NFT traders
5. /api/tile/{id}/history - Convenience endpoint combining all data
Test with known active tiles:
- Tile #1826 - Likely has multiple sales
- Tile #1984 - Popular tile
- Tile #0 - Corner tile, likely valuable
- Add database indexes on tile_id for all history tables
- Consider caching frequently accessed tile histories
- Implement pagination for tiles with extensive history
- Use database views for complex joins
func GetTilePurchaseHistory(c *gin.Context) {
tileID := c.Param("id")
purchases, err := db.GetPurchaseHistoryByTileId(ctx, tileID)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
// Add ENS resolution
for i, purchase := range purchases {
purchases[i].SoldByEns = ensResolver.Resolve(purchase.SoldBy)
purchases[i].PurchasedByEns = ensResolver.Resolve(purchase.PurchasedBy)
}
c.JSON(200, gin.H{"purchases": purchases})
}