Skip to content

Proposing Initiatives

Function Signatures

Initiatives can include up to five optional attachments. Supply metadata via the _attachments array or pass an empty array when no supporting materials are needed.

Basic Proposal

function proposeInitiative(
    Metadata calldata _metadata
) external returns (uint256 initiativeId)

Proposal with Lock

function proposeInitiativeWithLock(
    Metadata calldata _metadata,
    uint256 _amount,
    uint256 _lockDuration
) external returns (uint256 initiativeId, uint256 tokenId)

Parameters

ParameterTypeDescription
_metadataMetadataInitiative metadata (title, body, attachments). Title must be non-empty; attachments max 5 with non-empty URIs
_amountuint256Amount of tokens to lock (in wei, e.g., 100000 * 1e18)
_lockDurationuint256Duration to lock tokens, measured in intervals (must be > 0 and ≤ maxLockIntervals)

Metadata Struct

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

Title must be non-empty; body may be empty. Attachments are optional, capped at 5, and must have non-empty URIs.

Attachment Struct

struct Attachment {
    string uri;
    string mimeType;
    string description;
}
  • Maximum of 5 attachments per initiative
  • uri must be provided for each attachment; mimeType and description are optional helpers for clients

Returns

  • initiativeId - ID of the newly created initiative
  • tokenId - ERC721 NFT representing the lock position (only for proposeInitiativeWithLock)

Metadata storage: metadata is emitted in InitiativeProposed and not stored on-chain.

Initiative Data Structure

struct Initiative {
    InitiativeState state;           // Current state (Proposed, Accepted, Cancelled, Expired)
    address proposer;                // Proposer address
    uint256 timestamp;               // Creation timestamp
    uint256 lastActivity;            // Last activity timestamp
    uint256 acceptanceTimestamp;     // When accepted (0 if not yet accepted)
}

Initiative States

enum InitiativeState {
    Proposed,    // Initial state, can receive support
    Accepted,    // Board owner accepted the initiative
    Cancelled,   // Reserved for future use
    Expired      // No activity for > inactivityTimeout
}

Proposer Requirements

struct ParticipantRequirements {
    address token;
    uint256 minBalance;
    uint256 minHoldingDuration;
    uint256 minLockAmount;
}
Eligibility rules derived from fields:
  • token is the ERC20/IVotes token used for eligibility checks (can differ from the underlying lock token).
  • minBalance == 0 and minHoldingDuration == 0: no balance requirement.
  • minBalance > 0 and minHoldingDuration == 0: current balance check only.
  • minBalance > 0 and minHoldingDuration > 0: historical balance check (requires IVotes on token).
  • minLockAmount enforces a minimum lock amount for proposeInitiativeWithLock.
Constraints:
  • token cannot be address(0).
  • minHoldingDuration > 0 requires minBalance > 0 and an IVotes-compatible token.
  • minLockAmount must be ≤ minBalance.

Events Emitted

InitiativeProposed

event InitiativeProposed(
    uint256 indexed initiativeId,
    address indexed proposer,
    Metadata metadata
)

InitiativeSupported

Emitted when using proposeInitiativeWithLock:

event InitiativeSupported(
    uint256 indexed initiativeId,
    address indexed supporter,
    uint256 tokenAmount,
    uint256 lockDuration,
    uint256 tokenId  // ERC721 NFT ID
)

Validation & Errors

ErrorCauseSolution
Signals_EmptyTitleOrBodyTitle is emptyProvide a non-empty title
Signals_IncorrectBoardStateBoard not openWait for board to open
Signals_InsufficientTokensBalance < required amountAcquire more tokens
Signals_InsufficientTokenDurationHaven't held tokens long enoughWait or use different account
Signals_InsufficientLockAmountLock amount below minLockAmountIncrease lock amount or update requirements
Signals_TokenHasNoCheckpointSupportToken doesn't support IVotesBoard misconfigured
Signals_InvalidArgumentsInvalid lock duration or attachment URIUse valid duration and attachment data
Signals_TokenTransferFailedToken transfer revertedCheck approval and balance
Signals_AttachmentLimitExceededMore than 5 attachments providedTrim the attachment list before submitting

Helper Functions

// Check if address can propose with a given lock amount
function accountCanPropose(address account, uint256 lockAmount) external view returns (bool)
 
// Get current proposer requirements
function getProposerRequirements() external view returns (ParticipantRequirements memory)
 
// Get board configuration
function getBoardConfig() external view returns (BoardConfig memory)

Token approval: proposeInitiativeWithLock requires the caller to approve the Signals contract for _amount on the underlying ERC20.