Skip to main content
Build comprehensive Web3 developer profiles by verifying GitHub contributions and creating portable on-chain credentials. This guide covers integration patterns for developer communities, bounty platforms, and professional reputation systems.

Use Case Overview

GitHub credential attestations transform code contributions into verifiable digital assets that follow developers across platforms. Create meritocratic systems based on actual contribution history rather than self-reported skills. Ideal For:
  • Developer community platforms
  • Bounty and grants programs
  • Technical hiring and recruitment
  • Open source contribution tracking
  • Developer reputation systems
  • Hackathon team formation

Implementation

Schema Configuration

Define GitHub contribution attestation schemas:
// Basic GitHub profile verification
const githubProfileSchema = 'github-profile-v1';
// Definition: username:string,verified:bool,publicRepos:uint16,followers:uint16,totalCommits:uint32,accountAge:uint32,timestamp:uint64

// Repository contribution tracking
const repoContributionSchema = 'github-repo-contribution-v1';
// Definition: username:string,repoName:string,commits:uint16,additions:uint32,deletions:uint32,pullRequests:uint16,issues:uint16,timestamp:uint64

// Skill verification based on code analysis
const skillVerificationSchema = 'github-skill-verification-v1';
// Definition: username:string,language:string,linesOfCode:uint32,repositories:uint16,complexity:uint8,recentActivity:bool,timestamp:uint64

// Open source maintainer credentials
const maintainerSchema = 'github-maintainer-v1';
// Definition: username:string,repoName:string,role:string,stars:uint16,forks:uint16,contributors:uint16,maintainerSince:uint64,timestamp:uint64

GitHub Oracle Authority

Implement automated GitHub data verification:
import { StellarAttestSDK, SolanaAttestSDK } from '@attestprotocol/sdk';
import { Octokit } from '@octokit/rest';

class GitHubCredentialOracle {
  private sdk: StellarAttestSDK | SolanaAttestSDK;
  private github: Octokit;
  private rateLimiter: RateLimiter;
  
  constructor(
    sdk: StellarAttestSDK | SolanaAttestSDK,
    githubToken: string
  ) {
    this.sdk = sdk;
    this.github = new Octokit({ auth: githubToken });
    this.rateLimiter = new RateLimiter({ tokensPerInterval: 5000, interval: 'hour' });
  }
Main Verification Flow
  async verifyAndAttestGitHubProfile(
    userAddress: string,
    githubUsername: string,
    verificationProof: string
  ): Promise<GitHubVerificationResult> {
    const sessionId = `github-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    
    try {
      // Step 1: Verify the user owns the GitHub account
      await this.verifyAccountOwnership(githubUsername, verificationProof, userAddress);
      
      // Step 2: Gather comprehensive GitHub data
      const analysisResults = await this.performGitHubAnalysis(githubUsername);
      
      // Step 3: Create all attestations
      const attestations = await this.createAllAttestations(
        userAddress, 
        githubUsername, 
        analysisResults, 
        sessionId
      );
      
      return {
        success: true,
        sessionId,
        ...attestations,
        profileData: analysisResults.profileData,
        expiresAt: Date.now() + (90 * 24 * 60 * 60 * 1000) // 90 days
      };
      
    } catch (error) {
      await this.logVerificationError(sessionId, githubUsername, error);
      throw error;
    }
  }
GitHub Data Analysis
  private async performGitHubAnalysis(githubUsername: string) {
    // Gather all GitHub data in parallel for efficiency
    const [profileData, contributionData, skillData] = await Promise.all([
      this.gatherProfileData(githubUsername),
      this.analyzeContributions(githubUsername),
      this.analyzeSkills(githubUsername)
    ]);
    
    return { profileData, contributionData, skillData };
  }
Attestation Creation
  private async createAllAttestations(
    userAddress: string,
    githubUsername: string,
    analysisResults: any,
    sessionId: string
  ) {
    // Create profile attestation
    const profileAttestation = await this.createProfileAttestation(
      userAddress, githubUsername, analysisResults, sessionId
    );
    
    // Create skill attestations in parallel
    const [skillAttestations, repoAttestations] = await Promise.all([
      this.createSkillAttestations(userAddress, githubUsername, analysisResults.skillData, sessionId),
      this.createRepositoryAttestations(userAddress, githubUsername, analysisResults.contributionData.repositories, sessionId)
    ]);
    
    return {
      profileAttestation: profileAttestation,
      skillAttestations,
      repoAttestations
    };
  }
Profile Attestation Creation
  private async createProfileAttestation(
    userAddress: string,
    githubUsername: string,
    analysisResults: any,
    sessionId: string
  ): Promise<string> {
    const { profileData, contributionData } = analysisResults;
    
    // Create structured profile attestation value
    const profileValue = [
      `username:${githubUsername}`,
      `verified:true`,
      `publicRepos:${profileData.publicRepos}`,
      `followers:${profileData.followers}`,
      `totalCommits:${contributionData.totalCommits}`,
      `accountAge:${profileData.accountAge}`,
      `timestamp:${Math.floor(Date.now() / 1000)}`
    ].join(',');
    
    const attestation = await this.sdk.attest({
      schemaUID: 'github-profile-v1',
      subject: userAddress,
      value: profileValue,
      reference: sessionId
    });
    
    if (attestation.error) {
      throw new Error(`Profile attestation failed: ${attestation.error}`);
    }
    
    return attestation.data;
  }
}

**Account Ownership Verification**

```typescript
  private async verifyAccountOwnership(
    username: string,
    proof: string,
    walletAddress: string
  ): Promise<boolean> {
    try {
      // Support multiple verification methods
      if (proof.startsWith('gist:')) {
        return await this.verifyGistOwnership(username, proof, walletAddress);
      }
      
      if (proof.startsWith('commit:')) {
        return await this.verifyCommitOwnership(username, proof, walletAddress);
      }
      
      throw new Error('Unsupported verification method');
      
    } catch (error) {
      console.error('Ownership verification failed:', error);
      return false;
    }
  }
Gist Verification Method
  private async verifyGistOwnership(
    username: string, 
    proof: string, 
    walletAddress: string
  ): Promise<boolean> {
    const gistId = proof.replace('gist:', '');
    
    // Fetch the gist from GitHub
    const gist = await this.github.gists.get({ gist_id: gistId });
    
    // Verify gist owner matches claimed username
    if (gist.data.owner?.login !== username) {
      console.log('Gist owner mismatch');
      return false;
    }
    
    // Check if any gist file contains the wallet address
    const gistFiles = Object.values(gist.data.files || {});
    const hasWalletAddress = gistFiles.some(file => 
      file?.content?.includes(walletAddress)
    );
    
    return hasWalletAddress;
  }
Commit Verification Method
  private async verifyCommitOwnership(
    username: string,
    proof: string,
    walletAddress: string
  ): Promise<boolean> {
    const [, repo, sha] = proof.split(':');
    
    // Fetch the specific commit
    const commit = await this.github.repos.getCommit({
      owner: username,
      repo,
      ref: sha
    });
    
    // Verify commit message contains wallet address
    const commitMessage = commit.data.commit.message;
    return commitMessage.includes(walletAddress);
  }
}

**Profile Data Collection**

```typescript
  private async gatherProfileData(username: string): Promise<GitHubProfileData> {
    // Rate limit protection
    await this.rateLimiter.removeTokens(1);
    
    // Fetch user profile and repositories in parallel
    const [profile, repos] = await Promise.all([
      this.github.users.getByUsername({ username }),
      this.github.repos.listForUser({
        username,
        type: 'owner',
        sort: 'updated',
        per_page: 100
      })
    ]);
    
    // Calculate account age in days
    const accountAge = Math.floor(
      (Date.now() - new Date(profile.data.created_at).getTime()) / (24 * 60 * 60 * 1000)
    );
    
    return {
      username,
      publicRepos: profile.data.public_repos,
      followers: profile.data.followers,
      following: profile.data.following,
      accountAge,
      repositories: repos.data,
      bio: profile.data.bio,
      company: profile.data.company,
      location: profile.data.location
    };
  }
}
Contribution Analysis
  private async analyzeContributions(username: string): Promise<ContributionAnalysis> {
    await this.rateLimiter.removeTokens(2);
    
    // Get user's repositories
    const repos = await this.github.repos.listForUser({
      username,
      type: 'owner',
      per_page: 100
    });
    
    // Initialize tracking variables
    const analysisData = this.initializeAnalysisData();
    
    // Analyze top 20 repositories (to stay within rate limits)
    const topRepos = repos.data.slice(0, 20);
    const repoAnalyses = await this.analyzeRepositoriesBatch(username, topRepos);
    
    // Aggregate results
    return this.aggregateContributionData(repoAnalyses, analysisData);
  }
Initialize Analysis Data
  private initializeAnalysisData() {
    return {
      totalCommits: 0,
      totalAdditions: 0,
      totalDeletions: 0,
      languageStats: {} as Record<string, number>,
      repositoryContributions: [] as RepositoryContribution[]
    };
  }
Repository Batch Analysis
  private async analyzeRepositoriesBatch(username: string, repos: any[]) {
    const repoAnalyses = [];
    
    // Process repositories sequentially to respect rate limits
    for (const repo of repos) {
      try {
        const analysis = await this.analyzeSingleRepository(username, repo);
        repoAnalyses.push(analysis);
      } catch (error) {
        console.warn(`Failed to analyze repo ${repo.name}:`, error);
        // Continue with other repositories
      }
    }
    
    return repoAnalyses;
  }
Single Repository Analysis
  private async analyzeSingleRepository(username: string, repo: any) {
    await this.rateLimiter.removeTokens(1);
    
    // Get commits for this repository
    const commits = await this.github.repos.listCommits({
      owner: username,
      repo: repo.name,
      author: username,
      per_page: 100
    });
    
    const repoCommits = commits.data.length;
    
    return {
      name: repo.name,
      commits: repoCommits,
      stars: repo.stargazers_count,
      forks: repo.forks_count,
      language: repo.language,
      lastUpdated: new Date(repo.updated_at).getTime()
    };
  }
Aggregate Analysis Results
  private aggregateContributionData(repoAnalyses: any[], analysisData: any): ContributionAnalysis {
    let totalCommits = 0;
    const languageStats: Record<string, number> = {};
    
    // Process each repository's analysis
    for (const repoAnalysis of repoAnalyses) {
      totalCommits += repoAnalysis.commits;
      
      // Track language usage by commit count
      if (repoAnalysis.language) {
        languageStats[repoAnalysis.language] = 
          (languageStats[repoAnalysis.language] || 0) + repoAnalysis.commits;
      }
      
      analysisData.repositoryContributions.push(repoAnalysis);
    }
    
    // Determine primary languages (top 5 by commits)
    const primaryLanguages = Object.entries(languageStats)
      .sort(([,a], [,b]) => b - a)
      .slice(0, 5)
      .map(([lang]) => lang);
    
    return {
      totalCommits,
      totalAdditions: 0, // Placeholder - would require additional API calls
      totalDeletions: 0, // Placeholder - would require additional API calls
      languageStats,
      repositories: analysisData.repositoryContributions,
      primaryLanguages
    };
  }
}
Skill Analysis
  private async analyzeSkills(username: string): Promise<SkillAnalysis> {
    // Use repository language data as proxy for skill analysis
    // In production, this would integrate with code analysis tools
    const contributions = await this.analyzeContributions(username);
    
    // Map languages to skill objects with proficiency levels
    const skills = Object.entries(contributions.languageStats).map(([language, commits]) => ({
      skill: language,
      level: this.calculateSkillLevel(commits),
      repositories: contributions.repositories.filter(r => r.language === language).length,
      totalCommits: commits,
      recentActivity: this.hasRecentActivity(contributions.repositories, language)
    }));
    
    return {
      skills,
      overallLevel: this.calculateOverallLevel(skills),
      specializations: skills.filter(s => s.level >= 7).map(s => s.skill)
    };
  }
Skill Level Calculation
  private calculateSkillLevel(commits: number): number {
    // Map commit count to skill proficiency levels
    if (commits >= 1000) return 10; // Expert
    if (commits >= 500) return 8;   // Advanced
    if (commits >= 200) return 6;   // Intermediate
    if (commits >= 50) return 4;    // Beginner
    return 2; // Novice
  }

  private calculateOverallLevel(skills: SkillData[]): number {
    if (skills.length === 0) return 0;
    
    const totalScore = skills.reduce((sum, skill) => sum + skill.level, 0);
    return Math.round(totalScore / skills.length);
  }
Recent Activity Check
  private hasRecentActivity(repositories: RepositoryContribution[], language: string): boolean {
    const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000);
    
    return repositories
      .filter(r => r.language === language)
      .some(r => r.lastUpdated > thirtyDaysAgo);
  }
}
Skill Attestation Creation
  private async createSkillAttestations(
    userAddress: string,
    username: string,
    skillData: SkillAnalysis,
    sessionId: string
  ): Promise<string[]> {
    const attestations: string[] = [];
    
    // Filter skills with reasonable proficiency (level 4+)
    const qualifiedSkills = skillData.skills.filter(skill => skill.level >= 4);
    
    // Create attestations for each qualified skill
    for (const skill of qualifiedSkills) {
      try {
        const attestationUID = await this.createSingleSkillAttestation(
          userAddress, username, skill, sessionId
        );
        
        if (attestationUID) {
          attestations.push(attestationUID);
        }
      } catch (error) {
        console.warn(`Failed to create skill attestation for ${skill.skill}:`, error);
        // Continue with other skills
      }
    }
    
    return attestations;
  }
Single Skill Attestation
  private async createSingleSkillAttestation(
    userAddress: string,
    username: string,
    skill: SkillData,
    sessionId: string
  ): Promise<string | null> {
    // Estimate lines of code (rough approximation)
    const estimatedLOC = skill.totalCommits * 50;
    
    // Create structured skill attestation value
    const skillValue = [
      `username:${username}`,
      `language:${skill.skill}`,
      `linesOfCode:${estimatedLOC}`,
      `repositories:${skill.repositories}`,
      `complexity:${skill.level}`,
      `recentActivity:${skill.recentActivity}`,
      `timestamp:${Math.floor(Date.now() / 1000)}`
    ].join(',');
    
    const attestation = await this.sdk.attest({
      schemaUID: 'github-skill-verification-v1',
      subject: userAddress,
      value: skillValue,
      reference: `${sessionId}-skill-${skill.skill}`
    });
    
    return attestation.error ? null : attestation.data;
  }
}
Repository Attestation Creation
  private async createRepositoryAttestations(
    userAddress: string,
    username: string,
    repositories: RepositoryContribution[],
    sessionId: string
  ): Promise<string[]> {
    // Select top repositories by impact (stars + commits)
    const topRepos = this.selectTopRepositories(repositories, 10);
    
    const attestations: string[] = [];
    
    // Create attestations for each top repository
    for (const repo of topRepos) {
      try {
        const attestationUID = await this.createSingleRepoAttestation(
          userAddress, username, repo, sessionId
        );
        
        if (attestationUID) {
          attestations.push(attestationUID);
        }
      } catch (error) {
        console.warn(`Failed to create repo attestation for ${repo.name}:`, error);
      }
    }
    
    return attestations;
  }
Select Top Repositories
  private selectTopRepositories(repositories: RepositoryContribution[], limit: number) {
    return repositories
      .sort((a, b) => {
        // Score based on stars and commits
        const scoreA = a.stars + a.commits;
        const scoreB = b.stars + b.commits;
        return scoreB - scoreA;
      })
      .slice(0, limit);
  }
Single Repository Attestation
  private async createSingleRepoAttestation(
    userAddress: string,
    username: string,
    repo: RepositoryContribution,
    sessionId: string
  ): Promise<string | null> {
    // Create structured repository attestation value
    const repoValue = [
      `username:${username}`,
      `repoName:${repo.name}`,
      `commits:${repo.commits}`,
      `additions:0`,  // Placeholder - would require additional API calls
      `deletions:0`,  // Placeholder - would require additional API calls
      `pullRequests:0`, // Placeholder - would require additional API calls
      `issues:0`,     // Placeholder - would require additional API calls
      `timestamp:${Math.floor(Date.now() / 1000)}`
    ].join(',');
    
    const attestation = await this.sdk.attest({
      schemaUID: 'github-repo-contribution-v1',
      subject: userAddress,
      value: repoValue,
      reference: `${sessionId}-repo-${repo.name}`
    });
    
    return attestation.error ? null : attestation.data;
  }
}
TypeScript Interfaces
interface GitHubProfileData {
  username: string;
  publicRepos: number;
  followers: number;
  following: number;
  accountAge: number;
  repositories: any[];
  bio: string | null;
  company: string | null;
  location: string | null;
}

interface ContributionAnalysis {
  totalCommits: number;
  totalAdditions: number;
  totalDeletions: number;
  languageStats: Record<string, number>;
  repositories: RepositoryContribution[];
  primaryLanguages: string[];
}

interface RepositoryContribution {
  name: string;
  commits: number;
  stars: number;
  forks: number;
  language: string | null;
  lastUpdated: number;
}

interface SkillAnalysis {
  skills: SkillData[];
  overallLevel: number;
  specializations: string[];
}

interface SkillData {
  skill: string;
  level: number;
  repositories: number;
  totalCommits: number;
  recentActivity: boolean;
}

interface GitHubVerificationResult {
  success: boolean;
  sessionId: string;
  profileAttestation: string;
  skillAttestations: string[];
  repoAttestations: string[];
  profileData: GitHubProfileData;
  expiresAt: number;
}

Developer Profile Consumer

Implement GitHub credential verification in applications:
class DeveloperProfileVerifier {
  private sdk: StellarAttestSDK | SolanaAttestSDK;
  
  constructor(sdk: StellarAttestSDK | SolanaAttestSDK) {
    this.sdk = sdk;
  }

  async getDeveloperProfile(userAddress: string): Promise<DeveloperProfile | null> {
    try {
      // Fetch the main GitHub profile attestation
      const attestationData = await this.fetchProfileAttestation(userAddress);
      if (!attestationData) return null;
      
      // Fetch supplementary data in parallel
      const [skills, repositories] = await Promise.all([
        this.getDeveloperSkills(userAddress),
        this.getRepositoryContributions(userAddress)
      ]);
      
      // Build complete profile object
      return this.buildCompleteProfile(userAddress, attestationData, skills, repositories);
      
    } catch (error) {
      console.error('Error fetching developer profile:', error);
      return null;
    }
  }
Profile Data Fetching
  private async fetchProfileAttestation(userAddress: string) {
    const profileResult = await this.sdk.fetchAttestation({
      schemaUID: 'github-profile-v1',
      subject: userAddress
    });
    
    // Validate attestation exists and is not revoked
    if (profileResult.error || !profileResult.data || profileResult.data.revoked) {
      return null;
    }
    
    return {
      parsed: this.parseAttestationData(profileResult.data.value),
      reference: profileResult.data.reference
    };
  }
Build Complete Profile
  private buildCompleteProfile(
    userAddress: string,
    attestationData: any,
    skills: VerifiedSkill[],
    repositories: VerifiedRepository[]
  ): DeveloperProfile {
    const { parsed, reference } = attestationData;
    
    return {
      address: userAddress,
      github: {
        username: parsed.username,
        verified: parsed.verified === 'true',
        publicRepos: parseInt(parsed.publicRepos),
        followers: parseInt(parsed.followers),
        totalCommits: parseInt(parsed.totalCommits),
        accountAge: parseInt(parsed.accountAge)
      },
      skills,
      repositories,
      overallScore: this.calculateDeveloperScore(parsed, skills, repositories),
      verifiedAt: parseInt(parsed.timestamp),
      attestationUID: reference
    };
  }

  async verifyDeveloperSkill(
    userAddress: string,
    requiredSkill: string,
    minimumLevel: number = 5
  ): Promise<boolean> {
    try {
      // This would require a more sophisticated query system
      // For now, we'll fetch all skill attestations and filter
      const skills = await this.getDeveloperSkills(userAddress);
      
      const skill = skills.find(s => s.language.toLowerCase() === requiredSkill.toLowerCase());
      return skill ? skill.level >= minimumLevel : false;
      
    } catch (error) {
      console.error('Skill verification failed:', error);
      return false;
    }
  }

  async getDeveloperSkills(userAddress: string): Promise<VerifiedSkill[]> {
    // In a real implementation, this would query multiple skill attestations
    // For now, we'll return a placeholder structure
    return [];
  }

  async getRepositoryContributions(userAddress: string): Promise<VerifiedRepository[]> {
    // In a real implementation, this would query repository contribution attestations
    return [];
  }

  private parseAttestationData(value: string): Record<string, string> {
    const pairs = value.split(',');
    const result: Record<string, string> = {};
    
    pairs.forEach(pair => {
      const [key, val] = pair.split(':');
      result[key] = val;
    });
    
    return result;
  }

  private calculateDeveloperScore(
    profile: any,
    skills: VerifiedSkill[],
    repositories: VerifiedRepository[]
  ): number {
    let score = 0;
    
    // Profile score (40% weight)
    score += Math.min(40, profile.totalCommits / 100); // Up to 40 points for commits
    score += Math.min(10, profile.followers / 10); // Up to 10 points for followers
    score += Math.min(10, profile.publicRepos / 5); // Up to 10 points for repos
    
    // Skills score (30% weight)
    const avgSkillLevel = skills.reduce((sum, skill) => sum + skill.level, 0) / skills.length || 0;
    score += (avgSkillLevel / 10) * 30;
    
    // Repository score (30% weight)
    const totalStars = repositories.reduce((sum, repo) => sum + repo.stars, 0);
    score += Math.min(30, totalStars / 10);
    
    return Math.round(Math.min(100, score));
  }
}
TypeScript Interfaces
interface DeveloperProfile {
  address: string;
  github: {
    username: string;
    verified: boolean;
    publicRepos: number;
    followers: number;
    totalCommits: number;
    accountAge: number;
  };
  skills: VerifiedSkill[];
  repositories: VerifiedRepository[];
  overallScore: number;
  verifiedAt: number;
  attestationUID: string;
}

interface VerifiedSkill {
  language: string;
  level: number;
  repositories: number;
  recentActivity: boolean;
}

interface VerifiedRepository {
  name: string;
  commits: number;
  stars: number;
  language: string;
}

Integration Patterns

Bounty Platform Integration

Use GitHub credentials for bounty eligibility:
class BountyPlatform {
  private profileVerifier: DeveloperProfileVerifier;
  
  constructor(sdk: StellarAttestSDK | SolanaAttestSDK) {
    this.profileVerifier = new DeveloperProfileVerifier(sdk);
  }

  async checkBountyEligibility(
    userAddress: string,
    bountyRequirements: BountyRequirements
  ): Promise<EligibilityResult> {
    const profile = await this.profileVerifier.getDeveloperProfile(userAddress);
    
    if (!profile) {
      return {
        eligible: false,
        reason: 'No verified GitHub profile found',
        suggestions: ['Complete GitHub verification to participate in bounties']
      };
    }
    
    const checks = {
      minimumCommits: profile.github.totalCommits >= bountyRequirements.minimumCommits,
      minimumRepos: profile.github.publicRepos >= bountyRequirements.minimumRepos,
      requiredSkills: bountyRequirements.requiredSkills.every(skill =>
        this.profileVerifier.verifyDeveloperSkill(userAddress, skill, bountyRequirements.minimumSkillLevel)
      ),
      accountAge: profile.github.accountAge >= bountyRequirements.minimumAccountAge
    };
    
    const failedChecks = Object.entries(checks)
      .filter(([, passed]) => !passed)
      .map(([check]) => check);
    
    return {
      eligible: failedChecks.length === 0,
      reason: failedChecks.length > 0 ? `Failed requirements: ${failedChecks.join(', ')}` : undefined,
      profile,
      score: profile.overallScore,
      suggestions: this.generateSuggestions(failedChecks, bountyRequirements)
    };
  }

  private generateSuggestions(
    failedChecks: string[],
    requirements: BountyRequirements
  ): string[] {
    const suggestions = [];
    
    if (failedChecks.includes('minimumCommits')) {
      suggestions.push(`Increase your GitHub activity. Need ${requirements.minimumCommits} total commits.`);
    }
    
    if (failedChecks.includes('requiredSkills')) {
      suggestions.push(`Develop proficiency in: ${requirements.requiredSkills.join(', ')}`);
    }
    
    if (failedChecks.includes('accountAge')) {
      suggestions.push('GitHub account too new. Continue building your development history.');
    }
    
    return suggestions;
  }
}

interface BountyRequirements {
  minimumCommits: number;
  minimumRepos: number;
  requiredSkills: string[];
  minimumSkillLevel: number;
  minimumAccountAge: number; // days
}

interface EligibilityResult {
  eligible: boolean;
  reason?: string;
  profile?: DeveloperProfile;
  score?: number;
  suggestions: string[];
}

Team Formation System

Enable skill-based team matching:
class DeveloperTeamMatcher {
  private profileVerifier: DeveloperProfileVerifier;
  
  constructor(sdk: StellarAttestSDK | SolanaAttestSDK) {
    this.profileVerifier = new DeveloperProfileVerifier(sdk);
  }

  async findTeammates(
    userAddress: string,
    projectRequirements: ProjectRequirements
  ): Promise<TeammateRecommendation[]> {
    const userProfile = await this.profileVerifier.getDeveloperProfile(userAddress);
    
    if (!userProfile) {
      throw new Error('User must have verified GitHub profile');
    }
    
    // In a real implementation, this would query a database of developer profiles
    const candidates = await this.getCandidateDevelopers(projectRequirements);
    
    return candidates
      .map(candidate => this.calculateCompatibility(userProfile, candidate, projectRequirements))
      .sort((a, b) => b.compatibilityScore - a.compatibilityScore)
      .slice(0, 10); // Top 10 matches
  }

  private calculateCompatibility(
    user: DeveloperProfile,
    candidate: DeveloperProfile,
    requirements: ProjectRequirements
  ): TeammateRecommendation {
    let score = 0;
    const reasons = [];
    
    // Skill complementarity
    const userSkills = new Set(user.skills.map(s => s.language));
    const candidateSkills = new Set(candidate.skills.map(s => s.language));
    const skillOverlap = new Set([...userSkills].filter(x => candidateSkills.has(x)));
    const skillComplementarity = new Set([...candidateSkills].filter(x => !userSkills.has(x)));
    
    // Prefer candidates with complementary skills
    score += skillComplementarity.size * 10;
    if (skillComplementarity.size > 0) {
      reasons.push(`Brings additional skills: ${Array.from(skillComplementarity).join(', ')}`);
    }
    
    // Experience level matching
    const experienceGap = Math.abs(user.overallScore - candidate.overallScore);
    if (experienceGap < 20) {
      score += 20;
      reasons.push('Similar experience level');
    }
    
    // Required skills coverage
    const requiredSkillsCovered = requirements.requiredSkills.filter(skill =>
      candidateSkills.has(skill)
    );
    score += requiredSkillsCovered.length * 15;
    
    if (requiredSkillsCovered.length > 0) {
      reasons.push(`Covers required skills: ${requiredSkillsCovered.join(', ')}`);
    }
    
    return {
      profile: candidate,
      compatibilityScore: Math.min(100, score),
      reasons,
      complementarySkills: Array.from(skillComplementarity),
      sharedSkills: Array.from(skillOverlap)
    };
  }

  private async getCandidateDevelopers(requirements: ProjectRequirements): Promise<DeveloperProfile[]> {
    // Placeholder - would query actual developer database
    return [];
  }
}

interface ProjectRequirements {
  requiredSkills: string[];
  teamSize: number;
  experienceLevel: 'junior' | 'mid' | 'senior' | 'mixed';
  duration: number; // days
}

interface TeammateRecommendation {
  profile: DeveloperProfile;
  compatibilityScore: number;
  reasons: string[];
  complementarySkills: string[];
  sharedSkills: string[];
}

Best Practices

Verification Security

Implement robust account ownership verification:
class SecureGitHubVerification {
  static async generateVerificationChallenge(
    userAddress: string
  ): Promise<VerificationChallenge> {
    const nonce = crypto.randomBytes(32).toString('hex');
    const timestamp = Math.floor(Date.now() / 1000);
    const message = `Verify GitHub account for wallet ${userAddress} at ${timestamp} with nonce ${nonce}`;
    
    return {
      challengeId: `gh-verify-${timestamp}-${nonce.slice(0, 8)}`,
      message,
      instructions: [
        'Create a public gist with the exact message above',
        'Or commit the message to any public repository',
        'Submit the gist ID or commit SHA as proof'
      ],
      expiresAt: timestamp + 3600 // 1 hour
    };
  }

  static async verifyChallenge(
    challenge: VerificationChallenge,
    proof: string,
    githubUsername: string
  ): Promise<boolean> {
    // Verify challenge hasn't expired
    if (Date.now() / 1000 > challenge.expiresAt) {
      return false;
    }
    
    // Verify proof contains challenge message
    // Implementation would check gist or commit content
    return true; // Placeholder
  }
}

interface VerificationChallenge {
  challengeId: string;
  message: string;
  instructions: string[];
  expiresAt: number;
}

Data Privacy

Protect sensitive GitHub data:
class PrivacyPreservingGitHub {
  static async createPrivateSkillAttestation(
    userAddress: string,
    skillData: SkillAnalysis,
    sdk: StellarAttestSDK | SolanaAttestSDK
  ): Promise<string> {
    // Only attest to skill levels without revealing specific repositories
    const skillSummary = skillData.skills.map(skill => ({
      skill: skill.skill,
      level: Math.floor(skill.level / 2) * 2, // Round to even numbers for privacy
      category: this.categorizeSkillLevel(skill.level)
    }));
    
    const attestation = await sdk.attest({
      schemaUID: 'github-skill-private-v1',
      subject: userAddress,
      value: `skillCount:${skillSummary.length},averageLevel:${Math.round(skillData.overallLevel)},specializations:${skillData.specializations.length},verified:true,timestamp:${Math.floor(Date.now() / 1000)}`,
      reference: `private-skills-${Date.now()}`
    });
    
    if (attestation.error) {
      throw new Error(`Private skill attestation failed: ${attestation.error}`);
    }
    
    return attestation.data;
  }

  private static categorizeSkillLevel(level: number): string {
    if (level >= 8) return 'expert';
    if (level >= 6) return 'advanced';
    if (level >= 4) return 'intermediate';
    return 'beginner';
  }
}

Next Steps