Use Case Overview
DAO voting attestations enable sophisticated governance models beyond simple token-weighted voting. Track contributions, verify membership, and implement reputation-based voting power. Ideal For:- DAOs requiring Sybil-resistant voting
- Contribution-based governance models
- Multi-tier membership systems
- Cross-DAO reputation portability
Implementation
Schema Selection
Choose or create schemas for your governance needs:Copy
// Basic DAO membership
const membershipSchema = 'dao-member-v1';
// Definition: isMember:bool,joinDate:uint64,role:string,votingPower:uint32
// Contribution tracking
const contributionSchema = 'dao-contribution-v1';
// Definition: totalContributions:uint32,codeCommits:uint16,proposalsSubmitted:uint16,lastActive:uint64
// Reputation scoring
const reputationSchema = 'dao-reputation-v1';
// Definition: score:uint16,participationRate:uint8,proposalSuccess:uint8,peerEndorsements:uint16
DAO Integration
Implement attestation-based governance:Copy
import { StellarAttestSDK, SolanaAttestSDK } from '@attestprotocol/sdk';
class AttestationDAO {
private sdk: StellarAttestSDK | SolanaAttestSDK;
private daoAddress: string;
constructor(sdk: StellarAttestSDK | SolanaAttestSDK, daoAddress: string) {
this.sdk = sdk;
this.daoAddress = daoAddress;
}
Copy
async grantMembership(memberAddress: string, role: string = 'member') {
// Verify membership proposal was approved through governance
const proposal = await this.getProposal(memberAddress);
if (!proposal.passed) {
throw new Error('Membership proposal not passed');
}
// Create membership attestation with role and base voting power
const membershipValue = [
`isMember:true`,
`joinDate:${Date.now()}`,
`role:${role}`,
`votingPower:1`
].join(',');
const attestation = await this.sdk.attest({
schemaUID: 'dao-member-v1',
subject: memberAddress,
value: membershipValue,
reference: `membership-${proposal.id}`
});
return attestation;
}
Copy
async calculateVotingPower(voterAddress: string): Promise<number> {
// Start with base membership check
const basePower = await this.getBaseMembershipPower(voterAddress);
if (basePower === 0) return 0; // Not a member
// Add contribution-based power
const contributionPower = await this.getContributionPower(voterAddress);
// Apply reputation multiplier
const totalPower = basePower + contributionPower;
const finalPower = await this.applyReputationMultiplier(voterAddress, totalPower);
// Cap maximum voting power to prevent concentration
return Math.min(finalPower, 100);
}
Copy
private async getBaseMembershipPower(voterAddress: string): Promise<number> {
const membership = await this.sdk.fetchAttestation({
schemaUID: 'dao-member-v1',
subject: voterAddress
});
if (!membership.data || membership.data.revoked) {
return 0; // Not a member
}
const memberData = this.parseAttestationData(membership.data.value);
return memberData.votingPower || 1;
}
Copy
private async getContributionPower(voterAddress: string): Promise<number> {
const contributions = await this.sdk.fetchAttestation({
schemaUID: 'dao-contribution-v1',
subject: voterAddress
});
if (!contributions.data || contributions.data.revoked) {
return 0;
}
const contribData = this.parseAttestationData(contributions.data.value);
let contributionPower = 0;
// Weight formula: 1 point per 10 general contributions
contributionPower += Math.floor(contribData.totalContributions / 10);
// Bonus points for different contribution types
contributionPower += contribData.codeCommits * 2; // 2 points per code commit
contributionPower += contribData.proposalsSubmitted * 3; // 3 points per proposal
return contributionPower;
}
Copy
private async applyReputationMultiplier(voterAddress: string, basePower: number): Promise<number> {
const reputation = await this.sdk.fetchAttestation({
schemaUID: 'dao-reputation-v1',
subject: voterAddress
});
if (!reputation.data || reputation.data.revoked) {
return basePower; // No multiplier, return base power
}
const repData = this.parseAttestationData(reputation.data.value);
// Reputation multiplier: 1.0x to 2.0x based on score (max 200)
const multiplier = 1 + (repData.score / 200);
return Math.floor(basePower * multiplier);
}
Copy
async castVote(
voterAddress: string,
proposalId: string,
vote: 'for' | 'against' | 'abstain'
) {
// Calculate voter's current voting power
const votingPower = await this.calculateVotingPower(voterAddress);
if (votingPower === 0) {
throw new Error('No voting power - membership or contributions required');
}
// Record the weighted vote
await this.recordVote({
proposalId,
voter: voterAddress,
vote,
power: votingPower,
timestamp: Date.now()
});
// Update member's participation metrics
await this.updateParticipation(voterAddress);
return {
proposalId,
vote,
votingPower,
txHash: 'vote_tx_hash'
};
}
Copy
private async updateParticipation(memberAddress: string) {
// Get current reputation or initialize defaults
const current = await this.sdk.fetchAttestation({
schemaUID: 'dao-reputation-v1',
subject: memberAddress
});
let reputation = {
score: 50, // Base score
participationRate: 0,
proposalSuccess: 0,
peerEndorsements: 0
};
if (current.data && !current.data.revoked) {
reputation = this.parseAttestationData(current.data.value);
}
// Reward participation with score increases
reputation.participationRate = Math.min(reputation.participationRate + 1, 100);
reputation.score = Math.min(reputation.score + 1, 200);
// Update reputation attestation
const reputationValue = [
`score:${reputation.score}`,
`participationRate:${reputation.participationRate}`,
`proposalSuccess:${reputation.proposalSuccess}`,
`peerEndorsements:${reputation.peerEndorsements}`
].join(',');
await this.sdk.attest({
schemaUID: 'dao-reputation-v1',
subject: memberAddress,
value: reputationValue,
reference: `reputation-update-${Date.now()}`
});
}
}
Contribution Tracking
Track and reward member contributions:Copy
class ContributionTracker {
async recordContribution(
contributor: string,
type: 'code' | 'proposal' | 'community' | 'content',
details: any
) {
// Get existing contribution history
const currentContributions = await this.getCurrentContributions(contributor);
// Update contribution counts based on type
const updatedContributions = this.updateContributionCounts(currentContributions, type);
// Create new attestation with updated counts
const attestation = await this.issueUpdatedAttestation(contributor, updatedContributions, type);
// Check if milestone rewards should be issued
await this.checkContributionRewards(contributor, updatedContributions);
return attestation;
}
Copy
private async getCurrentContributions(contributor: string) {
const existing = await this.sdk.fetchAttestation({
schemaUID: 'dao-contribution-v1',
subject: contributor
});
// Default values for new contributors
let contributions = {
totalContributions: 0,
codeCommits: 0,
proposalsSubmitted: 0,
lastActive: 0
};
// Parse existing data if available
if (existing.data && !existing.data.revoked) {
contributions = this.parseAttestationData(existing.data.value);
}
return contributions;
}
Copy
private updateContributionCounts(contributions: any, type: string) {
// Increment total contributions counter
contributions.totalContributions += 1;
contributions.lastActive = Date.now();
// Update specific contribution type counters
switch(type) {
case 'code':
contributions.codeCommits += 1;
break;
case 'proposal':
contributions.proposalsSubmitted += 1;
break;
case 'community':
// Community contributions count toward total only
break;
case 'content':
// Content contributions count toward total only
break;
}
return contributions;
}
Copy
private async issueUpdatedAttestation(contributor: string, contributions: any, type: string) {
// Create structured attestation value
const contributionValue = [
`totalContributions:${contributions.totalContributions}`,
`codeCommits:${contributions.codeCommits}`,
`proposalsSubmitted:${contributions.proposalsSubmitted}`,
`lastActive:${contributions.lastActive}`
].join(',');
const attestation = await this.sdk.attest({
schemaUID: 'dao-contribution-v1',
subject: contributor,
value: contributionValue,
reference: `contribution-${type}-${Date.now()}`
});
return attestation;
}
Copy
private async checkContributionRewards(contributor: string, contributions: any) {
// Define contribution milestones for rewards
const milestones = [10, 50, 100, 500, 1000];
// Check if current total hits a milestone
if (milestones.includes(contributions.totalContributions)) {
console.log(`Contributor ${contributor} reached ${contributions.totalContributions} contributions`);
await this.issueReward(contributor, `milestone-${contributions.totalContributions}`);
}
}
}
Cross-DAO Reputation
Enable portable reputation across DAOs:Copy
class CrossDAOReputation {
async aggregateReputation(memberAddress: string): Promise<{
totalScore: number;
daos: Array<{
dao: string;
score: number;
role: string;
}>;
}> {
// Get reputation data from all participating DAOs
const daoReputations = await this.fetchAllDAOReputations(memberAddress);
// Filter out null results and calculate totals
const validReputations = daoReputations.filter(r => r !== null);
const totalScore = validReputations.reduce((sum, r) => sum + r.score, 0);
return {
totalScore,
daos: validReputations
};
}
Copy
private async fetchAllDAOReputations(memberAddress: string) {
// Define participating DAOs and their reputation schemas
const participatingDAOs = [
{ name: 'TechDAO', schema: 'techdao-reputation-v1' },
{ name: 'DeFiDAO', schema: 'defidao-reputation-v1' },
{ name: 'ArtDAO', schema: 'artdao-reputation-v1' }
];
// Fetch reputation attestations from all DAOs in parallel
const reputations = await Promise.all(
participatingDAOs.map(async (dao) => {
return await this.fetchSingleDAOReputation(memberAddress, dao);
})
);
return reputations;
}
Copy
private async fetchSingleDAOReputation(memberAddress: string, dao: any) {
try {
const attestation = await this.sdk.fetchAttestation({
schemaUID: dao.schema,
subject: memberAddress
});
// Return parsed data if attestation exists and is valid
if (attestation.data && !attestation.data.revoked) {
const data = this.parseAttestationData(attestation.data.value);
return {
dao: dao.name,
score: data.score || 0,
role: data.role || 'member'
};
}
return null; // No valid reputation in this DAO
} catch (error) {
console.warn(`Failed to fetch reputation from ${dao.name}:`, error);
return null;
}
}
Copy
async issuePortableReputation(memberAddress: string) {
// Aggregate reputation across all DAOs
const aggregated = await this.aggregateReputation(memberAddress);
if (aggregated.daos.length === 0) {
throw new Error('No DAO reputation found for this member');
}
// Find highest scoring DAO for "topDAO" field
const topDAO = aggregated.daos.reduce((prev, current) =>
(current.score > prev.score) ? current : prev
);
// Create cross-DAO reputation attestation
const reputationValue = [
`totalScore:${aggregated.totalScore}`,
`daoCount:${aggregated.daos.length}`,
`topDAO:${topDAO.dao}`
].join(',');
const attestation = await this.sdk.attest({
schemaUID: 'cross-dao-reputation-v1',
subject: memberAddress,
value: reputationValue,
reference: `cross-dao-${Date.now()}`
});
return attestation;
}
}
Advanced Patterns
Quadratic Voting
Implement quadratic voting with attestations:Copy
async function calculateQuadraticVotes(
voterAddress: string,
votesToCast: number
): Promise<{ cost: number; allowed: boolean }> {
// Get voter's reputation score
const reputation = await sdk.fetchAttestation({
schemaUID: 'dao-reputation-v1',
subject: voterAddress
});
if (!reputation.data || reputation.data.revoked) {
return { cost: 0, allowed: false };
}
const repData = parseAttestationData(reputation.data.value);
const maxVotes = Math.floor(Math.sqrt(repData.score)); // Square root of reputation
if (votesToCast > maxVotes) {
return { cost: 0, allowed: false };
}
// Quadratic cost: n² tokens for n votes
const cost = votesToCast * votesToCast;
return { cost, allowed: true };
}
Delegation with Attestations
Enable vote delegation:Copy
// Delegation schema
const delegationSchema = {
name: 'vote-delegation-v1',
definition: 'delegator:address,delegate:address,startTime:uint64,endTime:uint64,scope:string'
};
async function delegateVotingPower(
delegator: string,
delegate: string,
duration: number = 30 * 24 * 60 * 60 * 1000 // 30 days
) {
// Verify delegator has voting power
const delegatorPower = await calculateVotingPower(delegator);
if (delegatorPower === 0) {
throw new Error('No voting power to delegate');
}
// Issue delegation attestation
const attestation = await sdk.attest({
schemaUID: 'vote-delegation-v1',
subject: delegate,
value: `delegator:${delegator},delegate:${delegate},startTime:${Date.now()},endTime:${Date.now() + duration},scope:all`,
reference: `delegation-${delegator}-to-${delegate}`
});
return attestation;
}
// Check delegated voting power
async function getTotalVotingPower(voterAddress: string): Promise<number> {
let totalPower = await calculateVotingPower(voterAddress);
// Add delegated power
const delegations = await sdk.fetchAttestation({
schemaUID: 'vote-delegation-v1',
subject: voterAddress
});
if (delegations.data && !delegations.data.revoked) {
const delegationData = parseAttestationData(delegations.data.value);
// Check if delegation is still valid
if (Date.now() <= delegationData.endTime) {
const delegatorPower = await calculateVotingPower(delegationData.delegator);
totalPower += delegatorPower;
}
}
return totalPower;
}
Sybil Resistance
Implement proof of humanity requirements:Copy
async function verifySybilResistance(memberAddress: string): Promise<{
isHuman: boolean;
verificationMethods: string[];
}> {
// Check multiple attestation types for Sybil resistance
const checks = await Promise.all([
// Proof of Humanity
sdk.fetchAttestation({
schemaUID: 'proof-of-humanity-v1',
subject: memberAddress
}),
// Social verification
sdk.fetchAttestation({
schemaUID: 'social-verification-v1',
subject: memberAddress
}),
// Biometric verification
sdk.fetchAttestation({
schemaUID: 'biometric-verification-v1',
subject: memberAddress
})
]);
const verificationMethods = [];
let verificationScore = 0;
checks.forEach((check, index) => {
if (check.data && !check.data.revoked) {
const data = parseAttestationData(check.data.value);
if (data.verified || data.isHuman) {
verificationScore += 1;
verificationMethods.push(['humanity', 'social', 'biometric'][index]);
}
}
});
return {
isHuman: verificationScore >= 2, // Require at least 2 verification methods
verificationMethods
};
}
Integration Examples
Snapshot Integration
Integrate with Snapshot for off-chain voting:Copy
class SnapshotAttestationStrategy {
async getVotingPower(
space: string,
network: string,
provider: any,
addresses: string[],
options: any,
snapshot: number
): Promise<Record<string, number>> {
const scores: Record<string, number> = {};
// Fetch attestations for all addresses
const attestationPromises = addresses.map(async (address) => {
const power = await this.calculateVotingPower(address);
scores[address] = power;
});
await Promise.all(attestationPromises);
return scores;
}
private async calculateVotingPower(address: string): Promise<number> {
// Implementation matches DAO voting power calculation
const dao = new AttestationDAO(sdk, 'dao_address');
return await dao.calculateVotingPower(address);
}
}
On-Chain Governor
Implement on-chain governance with attestations:Copy
// Stellar/Soroban Governor Contract
use soroban_sdk::{contractimpl, Address, Env};
pub struct Governor;
#[contractimpl]
impl Governor {
pub fn propose(
env: Env,
proposer: Address,
description: String,
actions: Vec<Action>
) -> Result<u64, Error> {
// Verify proposer has required reputation
let reputation = Self::get_reputation(&env, &proposer)?;
if reputation < MIN_PROPOSAL_REPUTATION {
return Err(Error::InsufficientReputation);
}
// Create proposal
let proposal_id = Self::create_proposal(&env, proposer, description, actions)?;
Ok(proposal_id)
}
pub fn cast_vote(
env: Env,
voter: Address,
proposal_id: u64,
support: u8
) -> Result<(), Error> {
// Get voting power from attestations
let voting_power = Self::get_voting_power(&env, &voter)?;
if voting_power == 0 {
return Err(Error::NoVotingPower);
}
// Record weighted vote
Self::record_vote(&env, proposal_id, voter, support, voting_power)?;
Ok(())
}
}
Testing Implementation
Copy
describe('DAO Voting Integration', () => {
let dao: AttestationDAO;
let contributionTracker: ContributionTracker;
let member: string;
beforeEach(async () => {
dao = new AttestationDAO(sdk, 'test_dao');
contributionTracker = new ContributionTracker(sdk);
member = 'test_member_address';
});
it('should grant membership and calculate voting power', async () => {
// Grant membership
await dao.grantMembership(member, 'contributor');
// Add contributions
await contributionTracker.recordContribution(member, 'code', {
commits: 5,
linesAdded: 500
});
// Calculate voting power
const power = await dao.calculateVotingPower(member);
expect(power).to.be.greaterThan(1); // More than base membership
});
it('should handle vote delegation', async () => {
const delegator = 'delegator_address';
const delegate = 'delegate_address';
// Setup delegator with voting power
await dao.grantMembership(delegator, 'member');
// Delegate voting power
await delegateVotingPower(delegator, delegate);
// Check delegate's total power
const delegatePower = await getTotalVotingPower(delegate);
expect(delegatePower).to.include.delegated.power;
});
});
Best Practices
Voting Power Caps
Prevent concentration of power:Copy
const VOTING_POWER_LIMITS = {
individual: 100, // Max 100 votes per individual
percentageOfTotal: 0.05 // Max 5% of total voting power
};
async function applyVotingCaps(
voterAddress: string,
calculatedPower: number,
totalDAOPower: number
): Promise<number> {
// Apply individual cap
let cappedPower = Math.min(calculatedPower, VOTING_POWER_LIMITS.individual);
// Apply percentage cap
const maxByPercentage = Math.floor(totalDAOPower * VOTING_POWER_LIMITS.percentageOfTotal);
cappedPower = Math.min(cappedPower, maxByPercentage);
return cappedPower;
}
Participation Incentives
Reward active participation:Copy
async function calculateParticipationRewards(memberAddress: string) {
const participation = await sdk.fetchAttestation({
schemaUID: 'dao-participation-v1',
subject: memberAddress
});
if (participation.data) {
const data = parseAttestationData(participation.data.value);
// Reward tiers based on participation rate
if (data.participationRate >= 90) {
return { tier: 'platinum', multiplier: 2.0 };
} else if (data.participationRate >= 70) {
return { tier: 'gold', multiplier: 1.5 };
} else if (data.participationRate >= 50) {
return { tier: 'silver', multiplier: 1.2 };
}
}
return { tier: 'bronze', multiplier: 1.0 };
}
Next Steps
- Custom Schema Design - Create governance-specific schemas
- Privacy Options - Anonymous voting implementations
- GitHub Credentials - Developer DAO integrations
- Cross-Chain Governance - Multi-chain DAO setups