Skip to content

Hackathon

Nostreum

A Nostr social client where a profile can carry a verified Ethereum address: the badge is backed by an on-chain proof the client checks, not by a claim a server repeats.

Jul 2025Three 1st prizes and one 3rd prize, NapulETH 2025NostrWeb3Security

Nostreum is a Nostr client with one thing other clients do not have: a verified badge that means something checkable. A profile linked to an Ethereum address shows as verified because the client read the proof from a contract, and a profile can be found by either identity.

Event
NapulETH 2025
Result
Three 1st prizes and one 3rd prize
Role
Team lead
Identity layer
nostr-linkr
Repository
VincenzoImp/nostreum
VincenzoImp/nostreumNostr social client with on-chain Ethereum identity verification, powered by nostr-linkr.TypeScript

The problem

A social identity is worth what its verification is worth. On a platform, a badge means the platform checked something and is telling you about it: you are trusting the platform, not the proof. Nostr removes the platform, and the badge goes with it: a client can show you a name, a picture and a Lightning address, all of them self-asserted.

What I built

A working client – global and following feeds, composing and publishing signed notes, reactions, profile pages – with the identity layer wired through it rather than bolted on.

Events arriving from relays have their signatures validated in the client, so a relay cannot insert a note attributed to somebody else. Profiles are checked against the nostr-linkr contract, and the ones carrying an on-chain link render a verified badge. Search resolves in both directions: give it a Nostr public key or an Ethereum address and it finds the same person.

The follow list is kept in local storage rather than published as a contact-list event, which keeps the client usable without writing anything to a relay.

Hard parts

The badge is only worth what the client verifies. The premise is that verification is not a server’s word, which means the client performs the contract lookup itself. It also means an unverified profile has to read as plainly unverified rather than merely less decorated: the absence of the badge is the informative case, and it is the easier one to get wrong. The badge also inherits the boundary of nostr-linkr: its contract is unaudited and deployed on Base Sepolia, so “verified” means the proof path succeeds, not that the identity layer is production-secure.

Validating every event on the receiving side. Relays are untrusted by construction, and a client that renders whatever it is handed will render forgeries. Checking each incoming signature costs work on the hot path of a feed; skipping it would make a verified badge meaningless in the very view that displays it.