A soulbound Solana badge for consistent, meaningful contribution — starting with open source. Built for the DEV Weekend Challenge: Passion Edition.
Digital achievements are usually transferable, sellable, or detached from the person who earned them. PassionProof explores the opposite idea: what if recognition for real contribution couldn't be traded? Every badge is a Token-2022 mint with Solana's NonTransferable extension, permanently locking it to the wallet that earned it — plus an on-chain reason field, so the badge is a verifiable record of a specific milestone, not just a picture.
Deployed and verified on devnet:
HSSLcVQmCdCo8qt9UBMSAL9vbqpxYLkCLHoz74dgrBE1
- Token-2022 NonTransferable extension — enforced at the protocol level;
any
TransferCheckedinstruction against the badge fails on-chain. - Token-2022 MetadataPointer + TokenMetadata extensions — metadata lives directly on the mint account, no external metadata program required.
- Custom metadata fields (
category,awarded_for,recipient,issued) — the "reason" a badge exists, written on-chain viaupdate_field.
create_badge_mint— creates the Token-2022 mint, initializes the NonTransferable + MetadataPointer extensions, sets name/symbol/uri, then writes the reason fields.mint_badge— mints exactly 1 unit into the recipient's associated token account. Because the mint is NonTransferable, the resulting token account is permanently soulbound.
This program was built, deployed, and tested using Solana Playground — a browser-based Anchor IDE that compiles and runs on Playground's own servers, with no local Rust/Solana toolchain required.
Why: a local build in WSL hit a hard blocker — a transitive dependency
required Cargo's edition2024 feature, which the Solana CLI's bundled
platform-tools compiler (Rust 1.79.0) doesn't support. Combined with an
unreliable network that repeatedly timed out on the ~375MB platform-tools
download, Playground was the faster, more reliable path for a weekend
deadline. (If you have a newer local toolchain with platform-tools that
supports edition2024, anchor build/anchor test should also work locally
— just note the local path isn't what was verified for this submission.)
To run it yourself in Playground:
- Go to beta.solpg.io and create a new Anchor project.
- Replace the default
src/lib.rswithprograms/passionproof/src/lib.rsfrom this repo. - Replace the default test file with
tests/passionproof.tsfrom this repo. - Connect/save a Playground wallet, and airdrop devnet SOL (
solana airdrop 2in the Playground terminal, or use faucet.solana.com if rate-limited). - Click Build, then Deploy (~2.1 SOL for initial deployment).
- Click Test.
The test suite does three things, all executed as real transactions against the deployed program on devnet:
- Creates the badge mint with real metadata (statix PR merge as the example).
- Mints the badge to a recipient wallet.
- Attempts to transfer it and asserts that the transfer fails — the
actual proof-of-concept the whole project rests on. The rejection comes
directly from the Token-2022 program:
Program log: Transfer is disabled for this mint
- Program account:
HSSLcVQmCdCo8qt9UBMSAL9vbqpxYLkCLHoz74dgrBE1 create_badge_minttransaction:2JcbBHty...— logs showInitializeNonTransferableMint,MetadataPointerInstruction::Initialize,InitializeMint2, and theTokenMetadataInstruction::UpdateFieldcalls writing each reason field.mint_badgetransaction:3NAjTLLF...
The awarded_for field is self-attested by whoever holds mint authority —
the program records what the contribution was, but doesn't independently
verify it against, say, the GitHub API. The trust model is the same as a
signed certificate: the record is permanent and tamper-proof once issued, but
the issuing authority is what backs the claim.
- GitHub-verified minting, so
awarded_forbecomes a verified fact instead of a self-attested string. - Frontend: connect wallet → "Mint PassionProof" → display badge + "Soulbound: Cannot Transfer" state.
- Streak tracking / multiple badge categories.
- A path from devnet to mainnet once the extension logic has more mileage.