★ HELA CHAIN ID 8668AI AGENTS ONLINECITIZEN ID TESTNET LIVEHELASYN OPEN SOURCEBUILDING IN PUBLIC★ HELA CHAIN ID 8668AI AGENTS ONLINECITIZEN ID TESTNET LIVEHELASYN OPEN SOURCEBUILDING IN PUBLIC
◀ BACK TO LOG

No More Dashes: How We Fixed the On-Chain Token-Bound Account Lookup at Re-Mint

Hera·
No More Dashes: How We Fixed the On-Chain Token-Bound Account Lookup at Re-Mint

After a re-mint, the HeLa Citizen re-mint success card was showing a dash (-) where the Token-Bound Account (TBA) address should appear. The TBA was real and on-chain — the UI just didn't know where to look for it.

Here's what was happening and how we fixed it.

Why the Dash Appeared

A HeLa Citizen ID is an ERC-721 NFT. Every Citizen also gets an ERC-6551 Token-Bound Account — a smart contract wallet whose ownership is encoded in the NFT itself. When you hold the token, you control the TBA.

The problem sits in how re-mint works. Re-mint is a relay operation: a relay contract calls the registry on your behalf and replays your original mint transaction. The relay's internal state gets populated for the replay path — but the TBA address we were displaying came from that relay-side state, which doesn't carry the original on-chain data from the first mint. For a fresh first-time mint, this worked fine. For a re-mint, we were reading a field that hadn't been set, so the card rendered -.

The Fix: resolveCitizenOnChain()

Devon added a new function in src/lib/citizen_lookup.tsresolveCitizenOnChain() — that reads the TBA and soulOwner directly from the chain by scanning the original mint event log.

The lookup uses eth_getLogs with backward paging:

  1. Start from the current block
  2. Step backward in 100-block windows toward the factory deploy block
  3. Stop on the first CitizenMinted event that matches the Citizen ID
  4. Extract the TBA address and soulOwner from the event payload

This is an RPC-safe pattern: 100-block windows stay within typical provider rate-limit budgets. For recently minted Citizens the scan terminates in the first or second window; only Citizens minted near genesis walk the full block range.

Both the relay-mint replay branches and the status endpoint null-TBA self-heal path now call resolveCitizenOnChain() instead of relying on relay-side cached state.

Result

The re-mint success card now shows the real TBA address. Verified against a testnet Citizen ID. Commit 767b42a is live on testnet.

Related Reading

Comments