Learn to build privacy-preserving identity verification with Self Protocol - from frontend QR codes to smart contract attestations on Celo.
πΊ New to Self? Watch the ETHGlobal Workshop first.
This main branch of the repo contains an example of onchain verification. If you would like to see an example with offchain/backend verification, please check out the 'backend-verification' branch.
- Node.js 20+
- Self Mobile App
- Celo wallet with testnet funds
# Clone the workshop repository
git clone <repository-url>
cd workshop
# Install frontend dependencies
cd app
npm install
cd ..
# Install contract dependencies
cd contracts
npm install
forge install foundry-rs/forge-stdNavigate to the contracts folder and configure deployment:
# Copy and configure environment
cp .env.example .envEdit .env with your values:
# Your private key (with 0x prefix)
PRIVATE_KEY=0xyour_private_key_here
# Network selection
NETWORK=celo-sepolia
# Scope calculation
SCOPE_SEED="self-workshop"Deploy the contract:
# Make script executable
chmod +x script/deploy-proof-of-human.sh
# Deploy contract (handles everything automatically)
./script/deploy-proof-of-human.sh
β οΈ Troubleshooting Celo Sepolia: If you encounter aChain 11142220 not supportederror when usingcelo-sepolia, update Foundry to version 0.3.0:foundryup --install 0.3.0
The script will:
- β Build contracts with Foundry
- β Deploy ProofOfHuman contract
- β Verify contract on CeloScan
- β Display deployment summary
Configure the frontend:
cd ../app # Go to app directory
cp .env.example .envEdit .env:
# Your deployed contract address from Step 2
# IMPORTANT: address should be lowercase
NEXT_PUBLIC_SELF_ENDPOINT=0xyour_contract_address
# App configuration
NEXT_PUBLIC_SELF_APP_NAME="Self Workshop"
NEXT_PUBLIC_SELF_SCOPE_SEED="self-workshop"# Navigate to app directory and start the Next.js development server
cd app
npm run devVisit http://localhost:3000 to see your verification application!
The Self SDK is configured in your React components (app/app/page.tsx):
import { SelfAppBuilder, countries } from '@selfxyz/qrcode';
const app = new SelfAppBuilder({
version: 2, // Always use V2
appName: process.env.NEXT_PUBLIC_SELF_APP_NAME,
scope: process.env.NEXT_PUBLIC_SELF_SCOPE_SEED,
endpoint: process.env.NEXT_PUBLIC_SELF_ENDPOINT, // Your contract address (lowercase)
logoBase64: "https://i.postimg.cc/mrmVf9hm/self.png", // Logo URL or base64
userId: userId, // User's wallet address or identifier
endpointType: "staging_celo", // "staging_celo" for testnet, "celo" for mainnet
userIdType: "hex", // "hex" for Ethereum addresses, "uuid" for UUIDs
userDefinedData: "Hola Buenos Aires!!!", // Optional custom data
disclosures: {
// Verification requirements (must match your contract config)
minimumAge: 18,
excludedCountries: [countries.UNITED_STATES], // Use country constants
// ofac: true, // Optional: OFAC compliance checking
// Optional disclosures (uncomment to request):
// name: true,
// issuing_state: true,
// nationality: true,
// date_of_birth: true,
// passport_number: true,
// gender: true,
// expiry_date: true,
}
}).build();Your contract extends SelfVerificationRoot (contracts/src/ProofOfHuman.sol):
contract ProofOfHuman is SelfVerificationRoot {
// Verification result storage
bool public verificationSuccessful;
address public lastUserAddress;
bytes32 public verificationConfigId;
constructor(
address identityVerificationHubV2Address,
string memory scopeSeed, // Seed used to generate scope
SelfUtils.UnformattedVerificationConfigV2 memory _verificationConfig
) SelfVerificationRoot(identityVerificationHubV2Address, scopeSeed) {
// Format and set verification config
verificationConfig = SelfUtils.formatVerificationConfigV2(_verificationConfig);
verificationConfigId = IIdentityVerificationHubV2(identityVerificationHubV2Address)
.setVerificationConfigV2(verificationConfig);
}
function customVerificationHook(
ISelfVerificationRoot.GenericDiscloseOutputV2 memory output,
bytes memory userData
) internal override {
// Store verification results
verificationSuccessful = true;
lastOutput = output;
lastUserAddress = address(uint160(output.userIdentifier));
emit VerificationCompleted(output, userData);
}
function getConfigId(
bytes32, /* destinationChainId */
bytes32, /* userIdentifier */
bytes memory /* userDefinedData */
) public view override returns (bytes32) {
return verificationConfigId;
}
}- Hub Address:
0x16ECBA51e18a4a7e61fdC417f0d47AFEeDfbed74 - RPC:
https://forno.celo-sepolia.celo-testnet.org - Explorer:
https://celo-sepolia.blockscout.com/ - Supports: Mock passports for testing
- Hub Address:
0xe57F4773bd9c9d8b6Cd70431117d353298B9f5BF - RPC:
https://forno.celo.org - Explorer:
https://celoscan.io - Supports: Real passport verification
- π± Telegram Community: Self Protocol Builders Group
- π Documentation: docs.self.xyz
- π₯ Workshop Video: ETHGlobal Buenos Aires
workshop/
βββ app/ # Next.js frontend application
β βββ app/
β β βββ page.tsx # Main QR code page with Self SDK integration
β β βββ layout.tsx # Root layout with metadata
β β βββ globals.css # Global styles
β β βββ verified/
β β βββ page.tsx # Success page after verification
β β βββ page.module.css # Success page styles
β βββ .env.example # Frontend environment template
β βββ package.json # Frontend dependencies
β βββ tailwind.config.ts # Tailwind CSS configuration
β βββ README.md # Frontend documentation
β
βββ contracts/ # Foundry smart contracts
β βββ src/
β β βββ ProofOfHuman.sol # Main verification contract
β βββ script/
β β βββ Base.s.sol # Base script utilities
β β βββ DeployProofOfHuman.s.sol # Foundry deployment script
β β βββ deploy-proof-of-human.sh # Automated deployment script
β βββ lib/ # Dependencies
β β βββ forge-std/ # Foundry standard library
β β βββ openzeppelin-contracts/ # OpenZeppelin contracts
β βββ .env.example # Contract environment template
β βββ foundry.toml # Foundry configuration
β βββ package.json # Contract dependencies
β βββ README.md # Contract documentation
β
βββ README.md # This file (workshop guide)
- Self Protocol Docs - Complete protocol documentation
- Contract Integration Guide - Smart contract specifics
- Frontend SDK Reference - Frontend integration details
- Disclosure Proofs - Available verification options
- Self on iOS - iOS App
- Self on Android - Android App