Beyond the Academic PDF Transcripts: The Evolution of CampusCred

CampusCred Platform Visual

What began as a mandatory final project for Course 02369 at DTU quickly spiraled out of control. CampusCred started with a simple objective: build a system to replace the archaic, easily forged PDF transcripts used by universities. It evolved into a 4,400-line full-stack prototype that bridges the gap between blockchain immutability and GDPR-compliant privacy.

While the "school project" requirements were modest, I wanted to solve the real-world friction of academic verification: the slow, manual "trust-but-verify" loop that recruiters hate.

The Architecture: A Hybrid Approach

One of the biggest misconceptions about blockchain credentials is that everything goes "on-chain." That is a privacy nightmare. We designed a Hybrid Architecture that leverages the best of both worlds:

To keep the codebase clean, we implemented a strict Service Layer Pattern in the Flask backend. Controllers (Routes) never talk to the database or blockchain directly. Instead, they delegate to specialized services:

# backend/app/services/blockchain.py

class BlockchainService:
    def mint_credential(self, student_address, metadata_uri):
        """
        Orchestrates the minting process via Web3.py.
        Handles nonce management and gas estimation automatically.
        """
        txn = self.contract.functions.safeMint(
            student_address, 
            metadata_uri
        ).build_transaction({
            'chainId': self.chain_id,
            'gas': 2000000,
            'nonce': self.w3.eth.get_transaction_count(self.deployer_address),
        })
        
        # Sign and send transaction
        signed_txn = self.w3.eth.account.sign_transaction(txn, self.private_key)
        return self.w3.eth.send_raw_transaction(signed_txn.rawTransaction)

Smart Contract: The "Soulbound" Logic

Standard NFTs are tradeable assets. Academic degrees are not. If a student can sell their degree on OpenSea, the system is broken. We implemented Soulbound Tokens by overriding the standard OpenZeppelin transfer logic.

Using the `_update` hook (modern OpenZeppelin syntax), we ensure tokens can only move during minting (`from == 0`) or burning (`to == 0`). Any other transfer attempts trigger a revert.

// contracts/CampusCred.sol

function _update(address to, uint256 tokenId, address auth) internal override returns (address) {
    address from = _ownerOf(tokenId);
    
    // Allow Minting (from 0x0) and Burning (to 0x0)
    // Block all other transfers
    if (from != address(0) && to != address(0)) {
        revert("CampusCred: Credentials are non-transferable");
    }
    
    return super._update(to, tokenId, auth);
}

The "Wallet-Free" Verification Challenge

The biggest barrier to Web3 adoption is UX. A recruiter will not install Metamask just to verify a candidate. We solved this with a Selective Disclosure System.

The student generates a temporary "Verifier Link" (valid for 15 minutes). The backend validates the student's wallet signature, generates a secure token, and serves a specialized view. This allows the recruiter to view PII and download a digitally signed PDF without ever touching a blockchain wallet.

Engineering Around Limitations: Headless Wallet Injection

This is where the project went deep. Testing a DApp (Decentralized App) end-to-end is notoriously difficult. Standard headless browsers (Chromium) controlled by Playwright do not support browser extensions like Metamask. This meant we couldn't easily automate the "Connect Wallet" or "Sign Transaction" flows.

We engineered a Playwright Injection Bypass. Instead of trying to control a GUI extension, we inject a mock Ethereum provider directly into the browser's `window` object before the app loads.

# tests/e2e/conftest.py

@pytest.fixture
def browser_context(playwright):
    browser = playwright.chromium.launch(headless=True)
    context = browser.new_context()
    
    # Inject the Mock Provider Shim
    # This tricks the frontend into thinking Metamask is present
    context.add_init_script("""
        window.ethereum = {
            isMetaMask: true,
            request: async ({ method, params }) => {
                if (method === 'eth_requestAccounts') {
                    return ['0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266']; // Hardhat Test Account
                }
                if (method === 'personal_sign') {
                    return '0xdeadbeef...'; // Mock signature
                }
                console.log('Mock Provider intercepted:', method);
                return null;
            }
        };
    """)
    return context

This bypass allowed us to achieve 74% test coverage, verifying the full user journey: from clicking "Connect Wallet" to Minting, in a headless CI/CD environment without manual intervention.

Future Roadmap

While the prototype is robust, the next steps involve deepening the trust layer:

Final Thoughts

CampusCred proves that with the right architecture, we can abstract away the complexity of blockchain while keeping its integrity. It was a "school project" that forced us to solve real engineering problems: from gas optimization to headless browser injection.