Contests

1. Introduction

Introduction to Contests

The Contests system is a cornerstone of the Common Protocol ecosystem, designed to foster vibrant community engagement through incentivized participation. By creating a transparent and fair competition platform, communities can encourage high-quality content creation, meaningful interaction, and decentralized curation.

At its core, the Contests mechanism allows communities to run competitions where members can submit content, vote on submissions, and earn rewards based on community consensus. This creates a positive feedback loop: content creators are motivated to produce valuable contributions, while community members are incentivized to participate in the curation process.

The system is built with flexibility in mind, supporting two distinct contest types to accommodate different community needs:

  • Recurring Contests: Ongoing, cyclical competitions that automatically reset after a predetermined interval. These are ideal for continuous community engagement and regular content production.

  • Single Contests: One-time events with a defined duration. These work well for special occasions, focused themes, or unique community initiatives.

Both contest types leverage the same foundational architecture while providing specific features tailored to their use cases.

Core Concepts

  • Content Submission: Community members can submit creative works, proposals, articles, or any other form of content (typically represented by URLs) to the active contest.

  • Voting Mechanism: Members use their voting power to support content they find valuable. The voting power is determined by configurable strategies, typically based on token holdings.

  • Winner Selection: At the conclusion of each contest period, winners are determined algorithmically based on the cumulative votes received. The system maintains a dynamically sorted list of top content.

  • Reward Distribution: Prizes are automatically distributed to winners and active voters according to predefined shares. This system supports both ERC20 tokens and native blockchain currencies.

  • Hooks System: The architecture incorporates pre/post action hooks for extending functionality, allowing communities to implement custom logic for content verification, voting requirements, and reward distribution.

  • Voting Strategies: Pluggable strategies determine how voting power is calculated. This can be based on namespace token holdings, ERC20 balances, or custom criteria.

  • Fee Management: The system integrates with FeeManager contracts to handle the collection and distribution of fees, with a portion allocated to contest prizes.

Contest Creation Flows

Creating a Single Contest

  1. Preparation: Community admin determines contest parameters, including duration, token type, winner distribution, and voting strategy.

  2. Deployment: The admin calls newSingleContest through the NamespaceFactory, which uses ContestFactoryUtils to deploy a new ContestGovernorSingle contract.

  3. Configuration: The system automatically configures the contest with the specified parameters, including hooks for content and claim validation.

  4. Activation: The contest begins immediately upon deployment and runs for the specified duration.

  5. Finalization: After the contest period ends, the contract triggers winner determination and reward distribution.

Creating a Recurring Contest

  1. Preparation: Community admin determines contest parameters, including interval, token type, prize share, and voting strategy.

  2. Deployment: The admin calls newContest through the NamespaceFactory, which deploys a new ContestGovernor contract.

  3. Configuration: The system configures the contest with the specified parameters and integrates it with the community's FeeManager.

  4. Cycle Management: The contest runs in cycles of the specified interval length, automatically transitioning between periods.

  5. Continuous Operation: The contest continues indefinitely, with each cycle determining new winners and distributing rewards.

2. Deployments

Last Updated: March 14, 2025

Contract Addresses

Network
ContestFactory
NamespaceVoteStrategy
ERC20VoteStrategy
SequencerHook

Arbitrum

0x9ed281E62dB1b1d98aF90106974891a4c1cA3a47

0xedf43C919f59900C82d963E99d822dA3F95575EA

0x335b2259a060ce822e4bb8D73Ded366b9aD1CF94

0x1a651156Ecd9Be8d3067e15a2CC1044Ac6E8eCd7

Linea

0x9ed281e62db1b1d98af90106974891a4c1ca3a47

0xedf43c919f59900c82d963e99d822da3f95575ea

0x335b2259a060ce822e4bb8d73ded366b9ad1cf94

0x1a651156ecd9be8d3067e15a2cc1044ac6e8ecd7

Optimism

0x9ed281e62db1b1d98af90106974891a4c1ca3a47

0xedf43c919f59900c82d963e99d822da3f95575ea

0x335b2259a060ce822e4bb8d73ded366b9ad1cf94

0x1a651156ecd9be8d3067e15a2cc1044ac6e8ecd7

Ethereum

0xe979020f0a25efd14e9f3a339670f039ad5e7eca

0xd9e8bbe8949bfdcd0449152f6dbb66094c1ad96d

0x8829b650ff249afae20ad65bc490835b1f21fcf2

0x3ed1f8d63370a61dab9083472e637b0851b65567

BSC

0x1a651156ecd9be8d3067e15a2cc1044ac6e8ecd7

0x2a679d6f44dd1de40e24b10c59fab30c780c31ec

0xedf43c919f59900c82d963e99d822da3f95575ea

0x335b2259a060ce822e4bb8d73ded366b9ad1cf94

Base

0xe979020f0a25efd14e9f3a339670f039ad5e7eca

0x8829b650fF249AFae20AD65BC490835B1F21fcf2

0x7c702240bFdfF374798E48c892cE6a687D319e7f

-

Standard System Parameters

  • Protocol Fee: Configurable per deployment, typically 1-5%

  • Default Voter Share: 30% (percentage of contest prize distributed to voters)

  • Minimum Winner Shares: The shares for each winner must sum to 100

  • Default Contest Interval: 7 days (for recurring contests)

  • Default Voting Strategies: Namespace token holdings

Common Contest Parameters

Parameter
Configurable By
Description
Typical Values

Winner Shares

Contest Creator

Distribution percentages for top-ranked content (must sum to 100)

[50, 30, 20] for 3 winners

Voter Share

Contest Creator

Percentage of prize distributed to voters

30%

Token Type

Contest Creator

Currency used for contest rewards

Native (ETH/MATIC) or ERC20

Protocol Fee

Protocol Admin Only

Fee taken by the protocol from prizes (set at factory level)

1-5%

Contest Duration/Interval

Contest Creator

Duration for single contests or interval for recurring contests

7 days (604,800 seconds)

3. Single Contest Details

Single contests are one-time events with a defined duration, ideal for special occasions or focused community initiatives. They provide a complete contest lifecycle from creation to reward distribution within a fixed timeframe.

3.1 Events

Event Name
Event Signature

NewSingleContestStarted

event NewSingleContestStarted(uint256 startTime, uint256 endTime)

ContentAdded

event ContentAdded(uint256 indexed contentId, address indexed creator, string url)

VoterVoted

event VoterVoted(address indexed voter, uint256 indexed contentId, uint256 votingPower)

TokenSwept

event TokenSwept(address token, uint256 amount)

TransferFailed

event TransferFailed(address token, address to, uint256 amount)

NewSingleContestStarted

Emitted when a single contest is initialized. Includes the contest's start time and end time.

ContentAdded

Emitted when new content is added to the contest. Provides the content ID, content creator's address, and URL reference.

VoterVoted

Emitted when a community member votes on content. Records the voter's address, the content ID being voted on, and the voting power used.

TokenSwept

Emitted when remaining tokens are swept from the contract after the contest ends. Includes the token address and amount recovered.

TransferFailed

Emitted if a token transfer fails during reward distribution. Includes the token address, intended recipient, and amount.

3.2 Contract Architecture

ContestGovernorSingle

The ContestGovernorSingle contract manages the entire lifecycle of a one-time contest, from content submission to reward distribution.

Contract Address: Deployed per contest

Key Features:

  • Fixed duration contest

  • Supports both ERC20 tokens and native currency (ETH, MATIC, etc.)

  • Dynamic winner selection based on votes

  • Automatic reward distribution at contest end

  • Built-in protection against re-entrancy attacks

  • Integration with hooks for customizable behavior

Contract State Variables:

  • startTime: Timestamp when the contest begins

  • endTime: Timestamp when the contest ends

  • contestLength: Duration of the contest in seconds

  • currMinWinVotes: Minimum votes required to be in the winners list

  • winnerIds: Array of content IDs with the highest votes

  • winnerShares: Array of percentage shares for each winner position

  • totalPrize: Total amount available for distribution

  • voterShare: Percentage of the prize allocated to voters

  • contestToken: Address of ERC20 token used (address(0) for native currency)

  • namespace: Address of the associated Namespace contract

  • votingStrategy: Contract that determines voting power

  • claimHook: Hook for customizing claim behavior

  • contentHook: Hook for customizing content submission and voting

  • protocolFeePercentage: Percentage fee taken by the protocol

  • protocolFeeDestination: Address receiving protocol fees

Access Control:

  • onlyAdmin: Restricted to holders of the admin token in the associated namespace

  • isValidContest: Checks if the contest is within its valid period

3.3 Main Functions

addContent

function addContent(address creator, string calldata url, bytes calldata data) external isValidContest returns(uint256)

Allows participants to submit new content to the contest. Returns the content ID.

Parameters:

  • creator: Address of the content creator

  • url: URL pointing to the content

  • data: Additional data related to the content

Requirements:

  • The contest must be active

  • The content hook must validate the submission

voteContent

function voteContent(address voter, uint256 id) external isValidContest

Allows participants to vote on submitted content.

Parameters:

  • voter: Address of the voter

  • id: ID of the content being voted on

Requirements:

  • The contest must be active

  • The voter must not have already voted on this content

  • The content must be valid and not marked as completed

  • The content hook must validate the vote

deposit

function deposit(uint256 amount) external payable isValidContest

Adds funds to the contest prize pool.

Parameters:

  • amount: Amount being deposited

Requirements:

  • For native currency, the sent value must match the amount

  • For ERC20 tokens, sufficient allowance must be granted to the contract

claimVoterRewards

function claimVoterRewards(address voter) public

Allows voters to claim their portion of the prize pool.

Parameters:

  • voter: Address of the voter claiming rewards

Requirements:

  • The contest must have ended

  • The voter must have voted for at least one winning content

  • Rewards must not have been previously claimed by this voter

endContest

function endContest() public isValidContest

Finalizes the contest if the duration has passed, triggering reward distribution.

Requirements:

  • Current time must be past the contest end time

sweepTokens

function sweepTokens(address tokenAddress) public

Recovers any remaining tokens after the contest has ended.

Parameters:

  • tokenAddress: Address of the token to recover (address(0) for native currency)

Requirements:

  • The contest must have ended

  • The token being swept cannot be the contest token

  • There must be a positive balance to sweep

3.4 User Flows

Content Submission Flow

  1. Preparation

    • Creator prepares content offchain (article, artwork, proposal, etc.)

    • Content is typically hosted on external platforms with a reference URL

  2. Submission

    • Creator or authorized agent calls addContent

    • Content hook validates the submission based on configured rules

    • System assigns a unique content ID

    • ContentAdded event is emitted

  3. Verification

    • Community members can view submitted content through the provided URL

    • Content remains available for voting throughout the contest period

Voting Flow

  1. Content Discovery

    • Community members browse submitted content

    • Typically facilitated through offchain interfaces

  2. Voting Decision

    • Member selects content they wish to support

    • Member initiates vote through interface or direct contract interaction

  3. Vote Processing

    • System calculates voting power based on the configured strategy

    • Voter's contribution is recorded and added to content's cumulative votes

    • Winners list is dynamically updated if necessary

    • VoterVoted event is emitted

  4. Position Updates

    • If the content receives enough votes, it may enter the winners list

    • Winners list is kept sorted with highest-voted content first

    • Minimum vote threshold for winners is updated as necessary

Reward Distribution Flow

  1. Contest Completion

    • Contest automatically ends when the predefined duration expires

    • Can be triggered manually by calling endContest

  2. Protocol Fee

    • If configured, protocol fee is deducted first

    • Fee is sent to the designated protocol fee destination

  3. Content Creator Rewards

    • System calculates reward for each winning content

    • Rewards are based on position in the winners list and configured shares

    • Each creator receives their share automatically

  4. Voter Rewards

    • Voters must claim rewards by calling claimVoterRewards

    • Reward is calculated based on voting power contributed to winning content

    • System ensures rewards can only be claimed once per voter

  5. Remaining Funds

    • Any unclaimed funds can be swept after contest completion

    • Swept funds are typically sent to the community's fee manager

3.5 Integration Examples

Creating a Single Contest

// Example parameters for creating a single contest
const contestParams = {
  length: 7 * 24 * 60 * 60, // 7 days in seconds
  voteStrategy: "0x8829b650fF249AFae20AD65BC490835B1F21fcf2", // ERC20VoteStrategy
  winnerShares: [50, 30, 20], // Top 3 winners with respective percentages
  contestToken: "0x0000000000000000000000000000000000000000", // Native currency
  voterShare: 30, // 30% of prize goes to voters
  namespace: "0xe3ae9569f4523161742414480f87967e991741bd" // Community namespace
};

// Call to factory through the namespace factory
await namespaceFactory.newSingleContest(
  "my-community", // Namespace name
  contestParams.length,
  contestParams.winnerShares,
  1, // Namespace token ID used for voting
  contestParams.voterShare,
  100, // Voting weight
  contestParams.contestToken
);

Submitting Content

// Submitting content to a contest
await contestContract.addContent(
  "0x123...abc", // Content creator address
  "https://content-platform.com/my-submission", // Content URL
  "0x" // Optional data
);

Voting on Content

// Voting on content
await contestContract.voteContent(
  "0x456...def", // Voter address
  42 // Content ID
);

4. Recurring Contest Details

Recurring contests are ongoing, cyclical competitions that automatically reset after a predetermined interval. They're designed for continuous community engagement and regular content production, creating a sustainable incentive mechanism for participation.

4.1 Events

Event Name
Event Signature

NewRecurringContestStarted

event NewRecurringContestStarted(uint256 indexed contestId, uint256 startTime, uint256 endTime)

ContentAdded

event ContentAdded(uint256 indexed contentId, address indexed creator, string url)

PrizeShareUpdated

event PrizeShareUpdated(uint256 newPrizeShare)

VoterVoted

event VoterVoted(address indexed voter, uint256 indexed contentId, uint256 contestId, uint256 votingPower)

TransferFailed

event TransferFailed(address token, address to, uint256 amount)

NewRecurringContestStarted

Emitted when a new contest cycle begins, either automatically after the previous contest ends or through manual initiation. Includes the contest ID, start time, and end time.

ContentAdded

Emitted when new content is added to a contest. Provides the content ID, creator's address, and URL reference.

PrizeShareUpdated

Emitted when an admin updates the percentage of collected fees to be distributed as prize money in future contest cycles.

VoterVoted

Emitted when a community member votes on content. Records the voter's address, content ID, contest ID, and voting power used.

TransferFailed

Emitted when a token transfer fails during reward distribution. Includes the token address, intended recipient, and amount.

4.2 Contract Architecture

ContestGovernor

The ContestGovernor contract manages recurring contests that automatically transition between contest periods after predetermined intervals.

Contract Address: Deployed per community

Key Features:

  • Automatic contest cycle management

  • Configurable prize share and interval

  • Support for both ERC20 tokens and native currency

  • Integration with community fee manager

  • Dynamic winner selection based on votes

  • Historical tracking of past contest winners

  • Extensible through hook system

Contract State Variables:

  • startTime: Timestamp when the current contest cycle began

  • endTime: Timestamp when the current contest cycle will end

  • contestInterval: Duration of each contest cycle in seconds

  • contestId: Counter of contest cycles, increments with each new cycle

  • currentContentId: Counter for content submissions

  • currMinWinVotes: Minimum votes needed to enter winners list

  • prizeShare: Percentage of available funds used for prizes

  • nextPrizeShare: Updated prize share for future contests

  • voterShare: Percentage of prize allocated to voters

  • winnerIds: Array of content IDs with highest votes in current contest

  • winnerShares: Array of percentage shares for each winner position

  • namespace: Associated Namespace contract

  • contestToken: Address of ERC20 token used (address(0) for native currency)

  • FeeMangerAddress: Address of fee manager for collecting contest funds

  • completedContests: Mapping of contest IDs to their results

  • protocolFeePercentage: Percentage fee taken by the protocol

  • protocolFeeDestination: Address receiving protocol fees

Access Control:

  • onlyAdmin: Restricted to holders of the admin token in the associated namespace

  • isValidContest: Checks if the contest is within its valid period, triggers new cycle if needed

4.3 Main Functions

addContent

function addContent(address creator, string calldata url, bytes calldata data) external isValidContest returns(uint256)

Allows participants to submit new content to the current contest. Returns the content ID.

Parameters:

  • creator: Address of the content creator

  • url: URL pointing to the content

  • data: Additional data related to the content

Requirements:

  • The contest must be active

  • The content hook must validate the submission

voteContent

function voteContent(address voter, uint256 id) external isValidContest

Allows participants to vote on submitted content.

Parameters:

  • voter: Address of the voter

  • id: ID of the content being voted on

Requirements:

  • The contest must be active

  • The content must not already be a winner from previous contests

  • The voter must not have already voted on this content

  • The content must be valid

  • The content hook must validate the vote

deposit

function deposit(uint256 amount) external payable

Adds funds to the contest prize pool.

Parameters:

  • amount: Amount being deposited

Requirements:

  • For native currency, the sent value must match the amount

  • For ERC20 tokens, sufficient allowance must be granted to the contract

claimVoterRewards

function claimVoterRewards(address voter) public

Allows voters to claim their portion of the prize pool from the most recently completed contest.

Parameters:

  • voter: Address of the voter claiming rewards

Requirements:

  • At least one contest must have been completed

  • The voter must have voted for at least one winning content in the last contest

  • Rewards must not have been previously claimed by this voter

updatePrizeShare

function updatePrizeShare(uint256 newShare) external onlyAdmin

Updates the percentage of collected fees that will be distributed as prize money in future contest cycles.

Parameters:

  • newShare: New prize share percentage (0-100)

Requirements:

  • Caller must be an admin of the namespace

  • New share must not exceed 100%

newContest

function newContest() public

Manually triggers a new contest cycle.

Requirements:

  • Current time must be past the end time of the current contest

getWinnerIds

function getWinnerIds() external view returns(uint256[] memory)

Returns the IDs of content currently winning the active contest.

getPastWinners

function getPastWinners(uint256 contestId) external view returns(uint256[] memory)

Retrieves the list of winners from a specific past contest.

Parameters:

  • contestId: ID of the past contest

4.4 User Flows

Contest Cycle Management Flow

  1. Initialization

    • Contest is deployed with initial parameters

    • First contest cycle begins immediately with specified duration

  2. Automatic Transition

    • When any function with isValidContest modifier is called after contest end time

    • System finalizes current contest, distributes rewards, and begins new cycle

    • Contest ID increments, and new start/end times are set

  3. Manual Transition

    • Administrator or any user can call newContest to trigger transition

    • Only works if current contest end time has passed

    • Same finalization process occurs as with automatic transition

  4. Historical Tracking

    • Completed contests and their winners are stored in the completedContests mapping

    • Historical data remains accessible through getPastWinners

Prize Pool Management Flow

  1. Fee Collection

    • Funds are collected through FeeManager contract

    • Percentage specified by prizeShare is allocated to contest prizes

  2. Direct Deposits

    • Additional funds can be added through the deposit function

    • Both native currency and ERC20 tokens supported

  3. Prize Share Updates

    • Admin can modify prize share percentage through updatePrizeShare

    • Changes take effect in the next contest cycle

  4. Reward Distribution

    • At contest end, protocol fee is deducted if configured

    • Content creator rewards are distributed automatically

    • Voter rewards must be claimed manually

    • Any unclaimed rewards carry forward to next contest

Content Submission and Voting Flow

  1. Content Submission

    • Creator or authorized agent calls addContent

    • Content hook validates the submission

    • Content ID assigned and ContentAdded event emitted

  2. Voting Process

    • Community members review submitted content

    • Members call voteContent to support preferred content

    • Voting power determined by configured strategy

    • Winners list updated based on cumulative votes

  3. Winner Determination

    • Winners are sorted based on cumulative votes

    • Top content (up to the number of winner shares) receive rewards

    • Content marked as winners cannot receive votes in future contests

4.5 Integration Examples

Creating a Recurring Contest

// Example parameters for creating a recurring contest
const contestParams = {
  interval: 7 * 24 * 60 * 60, // 7 days in seconds
  voteStrategy: "0xedf43C919f59900C82d963E99d822dA3F95575EA", // NamespaceVoteStrategy
  winnerShares: [50, 30, 20], // Top 3 winners with respective percentages
  id: 1, // Namespace token ID used for voting
  prizeShare: 70, // 70% of collected fees go to contest prizes
  voterShare: 30, // 30% of prize goes to voters
  feeShare: 50, // 50% of fees allocated to contest
  weight: 100 // Voting weight for namespace tokens
};

// Call to factory through the namespace factory
await namespaceFactory.newContest(
  "my-community", // Namespace name
  contestParams.interval,
  contestParams.winnerShares,
  contestParams.id,
  contestParams.prizeShare,
  contestParams.voterShare,
  contestParams.feeShare,
  contestParams.weight
);

Submitting Content

// Submitting content to a contest
await contestContract.addContent(
  "0x123...abc", // Content creator address
  "https://content-platform.com/my-submission", // Content URL
  "0x" // Optional data
);

Voting on Content

// Voting on content
await contestContract.voteContent(
  "0x456...def", // Voter address
  42 // Content ID
);

Claiming Voter Rewards

// Claiming rewards as a voter
await contestContract.claimVoterRewards(
  "0x456...def" // Voter address
);

Updating Prize Share (Admin Only)

// Update the prize share for future contests
await contestContract.updatePrizeShare(
  80 // 80% of collected fees will go to future contest prizes
);

5. Supporting Contracts

5.1 Voting Strategies

NamespaceVoteStrategy

Determines voting power based on Namespace token balances.

Key Features:

  • Configurable per contest

  • Voting power = token balance × weight

Key Functions:

  • calculateVotingPower: Calculates voter's power based on their token balance

  • addUpdateConfig: Configures which Namespace token is used for a contest

ERC20VoteStrategy

Determines voting power based on ERC20 token balances.

Key Features:

  • Configurable per contest

  • Support for standard ERC20 tokens

5.2 Hook Contracts

SequencerHook

Controls the sequencing of content and voting operations.

Key Features:

  • Restricts content submission and voting to authorized sequencers

  • Additional security layer for contest operations

ReferralClaimHook

Integrates with the referral system to distribute rewards.

Key Features:

  • Pre/post hooks for claiming rewards

  • Referral attribution for rewards

5.3 ContestFactoryUtils

Handles the deployment of new contest contracts.

Key Features:

  • Deploys both recurring and single contests

  • Configurable parameters for contest creation

  • Managed by the NamespaceFactory

6. Security Considerations

6.1 Re-entrancy Protection

Both contest types implement measures to prevent re-entrancy attacks:

  • ContestGovernorSingle uses a specific re-entrancy guard in critical functions

  • State changes are made before external calls

  • Proper checks-effects-interactions pattern is followed

6.2 Access Control

Access to administrative functions is restricted through:

  • onlyAdmin modifier requiring ownership of namespace admin token

  • Function-specific checks for authorized callers

  • Hook-based validation for content submissions and votes

6.3 Fund Security

The system ensures secure handling of funds through:

  • Separation of deposits and withdrawals

  • Verification of token transfers

  • Protocol fee enforcement

  • Configurable fee destinations

6.4 Contest Validity

Contest state is protected by:

  • Automatic transition between contest periods

  • Valid timeframe verification

  • Winner selection protection

  • Vote manipulation prevention

7. Best Practices for Implementation

7.1 Contest Configuration

  • Winner Distribution: Configure winner shares to incentivize quality content while encouraging broader participation

  • Contest Duration: Set appropriate durations based on community activity levels

  • Prize Share: Balance between immediate rewards and long-term incentives

  • Voting Strategy: Select the strategy that best aligns with community governance goals

7.2 Interface Integration

  • Provide easy-to-use interfaces for content submission and voting

  • Include content filtering and discovery mechanisms

  • Display real-time vote tallies and winner rankings

  • Implement reward claim notifications and history

7.3 Community Management

  • Regularly communicate contest themes and rules

  • Encourage diverse participation

  • Highlight winning content to drive engagement

  • Collect feedback on contest structure and rewards

  • Use analytics from past contests to optimize future parameters

Last updated

Was this helpful?