Months ago, I joined CKBuilders and started learning the blockchain properly, trying to consume as much as I could from the handbook and the wider ecosystem. A lot of the time, I would even ask myself if I was moving at pace or not.
Then I came across DOBs on CKB.
At the moment, the one idea I had was simple: an SBT. A soulbound token. Something non-transferable, identity-bound, participation-bound, and meaningful because it stays with the person who actually earned it. From there, I started sketching out what an SBT meant in my head, not just as a collectible, but as a proof layer.
That was where CKB PoP came in.
CKB PoP started as a way to prove presence. But while building it, it became obvious to me that āpresenceā is too narrow if the primitive is good enough. It should also be able to prove participation, completion, contribution, and all the other cases where someone should be able to earn a non-transferable badge on CKB without us pretending everything is just āattendanceā.
So I started scaffolding. And here we are today.
What CKB PoP is
CKB PoP is a scope-based participation system on CKB. By āscopeā, I mean the thing a badge is issued for. That scope might be:
- a physical event
- an online hackathon
- a program
- a course
- a campaign
- a bounty
- a membership
- or something custom
The core idea is that the on-chain primitive stays stable, while the way participation is proven can change depending on the use case. So instead of hardcoding one ritual, the system now supports different proof flows.
Right now, that includes:
- dynamic QR for physical presence
- signed claims for online completion
- submission proofs for async or reviewed work
- policy extensions for organizer attestations and submission review
So a conference check-in and an online hackathon completion can both lead to the same class of non-transferable badge, but through different proof paths.
The architecture
Iāve tried to keep the boundaries very explicit.
1. The package
I extracted the reusable part into an npm package called `ckb-pop-kit`. This is the reusable developer-facing layer. It handles things like:
- scope modeling
- proof driver registration
- policy extension registration
- claim token helpers
- manifest shaping
- CKB helper functions for args and cell data
The idea is that if another product wants to build on this, they should not need to depend on my frontend or hosted backend just to use the model.
2. The backend
The backend is a Rust service. It is non-authoritative. It does useful work, but it is not the final trust anchor.
It currently handles:
- scope creation
- HMAC encoded QR generation
- signed claim issuance and verification
- badge observation
- manifest discovery
- convenience APIs for the reference frontend
The backend can decide whether someone is eligible according to a given flow, but it still does not get to override the chain.
3. The contracts
The contracts are small on purpose. They enforce:
- uniqueness
- ownership
- immutability
They do not know whether the badge came from a summit, a hackathon, or a course. They do not know what āattendanceā means. They do not know what ācompletionā means. They only know that a badge exists, it is unique for a given scope and address, and it belongs to that address.
That separation matters to me.
4. The reference frontend
There is also a reference app on top of all this. It now demonstrates:
- physical verification flow
- online claim flow
- scope creation
- badge vault/gallery
- integration surface
I recently rebuilt the frontend shell and landing so it feels more intentional, and I also put docs for easy integrations.
One thing I cared about a lot
I did not want online participation to be hacked in as if it were just a weird event check-in. If someone completes an online hackathon, that should not have to masquerade as physical presence.
So the system now has explicit fields like:
- `scope_kind`
- `participation_mode`
That means the metadata can actually say what happened, instead of forcing everything into the vocabulary of attendance.
Why I think this matters on CKB
CKB is one of the few places where this kind of thing feels natural. The cell model makes it very clean to think in terms of unique owned artifacts. Type scripts let you enforce the invariants that should actually live on-chain, while keeping the rest off-chain and replaceable. That balance has become more and more important to me while building this. Not everything needs to be on-chain. But the things that matter should be enforceable there.
## Where it is now
At this point, CKB PoP has:
- a published npm package: `ckb-pop-kit`
- a reference backend
- contracts for badge uniqueness and scope anchors (testnet)
- physical QR flow
- online signed-claim flow
- docs and reference UI
- a model that is broader than just events
So it is no longer just āproof of physical presenceā. It is closer to a reusable participation primitive on CKB.
Links
- Reference App: https://ckb-pop.xyz
- Docs: https://docs.ckb-pop.xyz, Build on CKB-PoP
- npm package: https://www.npmjs.com/package/ckb-pop-kit
- GitHub: GitHub - RobaireTH/ckb-pop: Mint verifiable, non-transferable badges on CKB when you attend real-world events. Ā· GitHub
Where I need criticism
This is the part where I ask the community to really poke holes in it.
I want:
- technical criticism
- architectural criticism
- product criticism
- protocol criticism
- integration ideas
- security review
- docs feedback
- naming criticism too, honestly
And if anyone wants to contribute directly, Iām open to all sorts of contributions:
- code
- review
- design
- docs
- protocol feedback
- use-case suggestions
- corrections where Iām thinking wrongly
Iām especially interested in hearing from community builders who might want to integrate something like this into their own products, whether for hackathons, programs, campaigns, guilds, or other contribution systems.
Appreciation
A special appreciation to the ever supporting Nervos Community, @xujiandong for mentoring me and @neon.bit . Another round to everyone who will be contributing to my growth and to CKB-PoP moving forwards. I have quite some more interesting builds weād come back to but I am glad to share this, and quite ānervosā as well.
Btw, If you read this and something feels wrong, say it.If you think the model is solid but incomplete, say what is missing. If you think there is a better way to structure this on CKB, I want to hear that too. And if you think this can be useful in something youāre building, Iād like to talk.
