DEV Community

Cover image for PassionProof — A Soulbound NFT for Consistent Open Source Contribution
Lymah
Lymah Subscriber

Posted on

PassionProof — A Soulbound NFT for Consistent Open Source Contribution

DEV Weekend Challenge: Passion Edition Submission

This is a submission for Weekend Challenge: Passion Edition

What I Built

PassionProof is a Solana program that mints a soulbound badge for a real contribution, then makes it permanently, provably non-transferable.
Digital achievements are usually transferable, sellable, or detached from the person who earned them. I wanted to explore the opposite: what if recognition for real contribution couldn't be traded? PassionProof issues a Token-2022 badge that's locked to the wallet it was minted to, carrying an on-chain "reason" field recording exactly what it's for.

My own path into this space started as a self-taught, career-shifted developer — I hold a Biochemistry degree, not a CS one, and the thing that proved to me (and eventually to others) that I belonged in this field was becoming a core contributor to statix, a Nix linter now canonical in nixpkgs. That's the milestone I recorded in the badge below: awarded_for: "Merged first PR into statix". Passion isn't just saying you love something; it's showing up consistently for work that doesn't always get seen, and I wanted a way to make that kind of record permanent instead of just a line on a resume.

Demo

The recording walks through the real, on-chain test run: creating the badge mint, minting it to a recipient, then attempting to transfer it. Captions are on the video, but the key moment is worth pulling out here directly, at the point of the transfer attempt, the program log reads:

Program log: Transfer is disabled for this mint
Enter fullscreen mode Exit fullscreen mode

That's Token-2022 itself refusing the transfer at the protocol level, not a check written into my own program.

Program deployed to devnet:
HSSLcVQmCdCo8qt9UBMSAL9vbqpxYLkCLHoz74dgrBE1

Real transactions on devnet:

the deployed program account, confirming it's live and<br>
executable on devnet:

the create_badge_mint transaction log, showing the real<br>
Token-2022 instructions executed: InitializeNonTransferableMint,<br>
MetadataPointerInstruction::Initialize, InitializeMint2, and three<br>
TokenMetadataInstruction::UpdateField calls writing the category,<br>
awarded_for, and recipient/issued fields — all ending in<br>
Program returned success:

Code

PassionProof

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

What it uses

  • Token-2022 NonTransferable extension — enforced at the protocol level any TransferChecked instruction 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…

How I Built It

PassionProof is an Anchor program built on Solana's Token-2022 program,
using two of its extensions instead of a traditional NFT metadata standard:

  • NonTransferable extension — enforced at the protocol level. Once a badge mint has this extension, any transfer instruction against a token account holding it is rejected by the Token-2022 program itself. This isn't a convention or a frontend restriction; it's consensus-level.
  • MetadataPointer + TokenMetadata extensions — metadata lives directly on the mint account. No external metadata program, no off-chain indexer dependency for the core facts.

The program exposes two instructions:

pub fn create_badge_mint(
    ctx: Context<CreateBadgeMint>,
    name: String,
    symbol: String,
    uri: String,
    category: String,
    awarded_for: String,
    recipient_name: String,
) -> Result<()>

pub fn mint_badge(ctx: Context<MintBadge>) -> Result<()>
Enter fullscreen mode Exit fullscreen mode

create_badge_mint initializes the mint with both extensions, then writes custom metadata fields — category, awarded_for, recipient, and issued — directly into the mint's TLV metadata. mint_badge mints exactly one unit into the recipient's associated token account. Because the mint is NonTransferable, that token account is now permanently bound to that wallet.

One honest scope note: 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 is the natural next step.

Challenges — most of my actual weekend went into infrastructure, not logic, which felt worth being honest about:

  • Getting a local Anchor/Rust toolchain working in WSL hit a wall when a transitive dependency required Cargo's edition2024 feature, and the Solana CLI's bundled platform-tools compiler was too old to support it. Combined with unreliable network conditions that kept timing out large toolchain downloads, I switched to Solana Playground (a browser-based Anchor IDE) to build, deploy, and test — the right call for a tight weekend timeline.
  • Token-2022's metadata extension requires manually funding rent as the account grows (each metadata field write resizes the account), and I initially wrote a realloc call into my program that only the account's owning program (Token-2022, not mine) was actually allowed to perform. Solana enforces account ownership boundaries strictly.
  • Making sure my "transfer fails" test proved the right thing, my first few attempts failed for boring reasons (empty wallet, missing destination account) rather than the NonTransferable extension itself. It took a few iterations to isolate the actual protocol-level rejection.

What I'd build next:

  • GitHub-verified minting, so awarded_for becomes a verified fact instead of a self-attested string
  • A minimal frontend: connect wallet → "Mint PassionProof" → see the badge and its "Soulbound: Cannot Transfer" state
  • Support for multiple contribution categories beyond open source
  • A path from devnet to mainnet once the extension logic has more mileage

Prize Categories

Submitting to Best Use of Solana. PassionProof uses Solana's native Token-2022 program directly, the NonTransferable extension, the MetadataPointer extension, and the TokenMetadata interface with custom fields, with no external metadata program or Metaplex dependency.

Top comments (0)