Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

BoardConfig

struct BoardConfig {
    string version;
    address owner;
    address underlyingToken;
    uint256 opensAt;
    uint256 closesAt;
    Metadata boardMetadata;
    AcceptanceCriteria acceptanceCriteria;
    IAuthorizer.ParticipantRequirements proposerRequirements;
    IAuthorizer.ParticipantRequirements supporterRequirements;
    LockingConfig lockingConfig;
    DecayConfig decayConfig;
}

version

Off-chain compatibility marker. Current version: "0.3.2".

owner

Board controller. Can accept initiatives, close/cancel the board, and adjust timing parameters. Use a multisig or DAO governor contract for decentralized operation.

underlyingToken

ERC20 token used for locking and weight calculation. Cannot be address(0). This is the token supporters lock when backing initiatives.

opensAt

Timestamp when the board starts accepting proposals and support. Set to block.timestamp to open immediately, or a future timestamp to schedule.

closesAt

Timestamp when the board stops accepting new activity. Must be ≥ opensAt. Set to 0 for a board that never closes.

boardMetadata

struct Metadata {
    string title;
    string body;
    Attachment[] attachments;
}
 
struct Attachment {
    string uri;
    string mimeType;
    string description;
}

Title, body (markdown), and up to 5 attachments. Emitted in the BoardCreated event, not stored on-chain. uri must be non-empty (https://, ipfs://, or on-chain pointer). mimeType and description are optional hints for clients.

acceptanceCriteria

struct AcceptanceCriteria {
    AcceptancePermissions permissions;
    ThresholdOverride thresholdOverride;
    uint256 thresholdPercentTotalSupplyWAD;
    uint256 minThreshold;
}

Threshold

The effective threshold is the greater of two values:

threshold = max(totalSupply * thresholdPercentTotalSupplyWAD / 1e18, minThreshold)

thresholdPercentTotalSupplyWAD — Percentage of total token supply in WAD notation. 0.05e18 = 5%. Must be < 1e18.

minThreshold — Fixed minimum weight, used as a floor. Prevents dust attacks when total supply is low.

At least one must be non-zero.

Permissions

permissions and thresholdOverride control who can call acceptInitiative() and whether the threshold check applies:

permissionsthresholdOverrideWho can acceptThreshold required
PermissionlessNoneAnyoneYes, for everyone
PermissionlessOnlyOwnerAnyoneYes, but owner bypasses
OnlyOwnerNoneOwner onlyYes
OnlyOwnerOnlyOwnerOwner onlyNo (owner bypasses)

proposerRequirements

struct ParticipantRequirements {
    address token;
    uint256 minBalance;
    uint256 minHoldingDuration;
    uint256 minLockAmount;
}

Controls who can call proposeInitiative() and proposeInitiativeWithLock(). Immutable after deployment.

Fields

token — ERC20 checked for eligibility. Can differ from underlyingToken. Cannot be address(0).

minBalance — Minimum current balance required. When non-zero, checks IERC20(token).balanceOf(caller) >= minBalance.

minHoldingDuration — Minimum blocks the caller must have held minBalance. When non-zero, calls IVotes(token).getPastVotes(caller, block.number - minHoldingDuration). Requires minBalance > 0 and an ERC20Votes token.

minLockAmount — Minimum tokens to lock when proposing with lock. proposeInitiative() (without lock) reverts if minLockAmount > 0. Must be ≤ minBalance.

Eligibility modes

The mode is inferred from field values. There is no explicit enum.

minBalanceminHoldingDurationModeToken type
00Open access, anyone can participateAny ERC20
> 00Current balance checkAny ERC20
> 0> 0Historical balance check (snapshot)ERC20Votes required

For the historical balance mode, users must delegate their tokens (even to themselves) to activate checkpoints. Without delegation, getPastVotes returns zero.

Block time reference for minHoldingDuration

ChainBlock time~7 days~30 days
Ethereum12s50,400216,000
Base2s302,4001,296,000
Arbitrum~0.25s2,419,20010,368,000

supporterRequirements

Same IAuthorizer.ParticipantRequirements struct as above. Controls who can call supportInitiative(). Immutable after deployment.

Configured independently. A board can have strict proposer requirements (high balance, holding duration) with open supporter requirements (anyone can lock tokens).

lockingConfig

struct LockingConfig {
    uint256 lockInterval;
    uint256 maxLockIntervals;
    uint256 releaseLockDuration;
    uint256 inactivityTimeout;
}

lockInterval

Base time unit in seconds. Lock durations and decay calculations are measured in multiples of this value. Must be > 0.

maxLockIntervals

Maximum number of intervals a lock can span. Must be > 0. The maximum lock duration in seconds is lockInterval × maxLockIntervals.

Example: lockInterval = 1 days and maxLockIntervals = 365 allows locks up to 1 year.

releaseLockDuration

Additional delay in seconds after an initiative is accepted before supporters can redeem their tokens. Set to 0 for immediate release on acceptance.

This is separate from lock duration. A supporter's lock may have expired, but if the initiative was just accepted, they still wait releaseLockDuration before redeeming.

On a time-boxed board, setting releaseLockDuration ≥ the board duration prevents token recycling. Supporters cannot back one initiative, wait for acceptance, reclaim, and redirect to another before the board closes.

inactivityTimeout

Seconds of inactivity before the owner can expire an initiative via expireInitiative(). An initiative's lastActivity timestamp updates on creation and each time a supporter locks tokens.

expirable when: block.timestamp > lastActivity + inactivityTimeout

decayConfig

struct DecayConfig {
    DecayCurveType curveType;
    uint256[] params;
}

curveType0 = Linear, 1 = Exponential.

params — Curve-specific parameters:

  • Linear (0): params = [decayRate]. Rate of 1e18 = 1:1 decay per interval.
  • Exponential (1): params = [decayMultiplier]. Multiplier of 0.9e18 = 10% reduction per interval.