Skip to content

Supporting Initiatives

Function Signature

function supportInitiative(
    uint256 initiativeId,
    uint256 amount,
    uint256 lockDuration
) external returns (uint256 tokenId)

Parameters

ParameterTypeDescription
initiativeIduint256ID of the initiative to support (must exist and be in Proposed state)
amountuint256Amount of tokens to lock (in wei, e.g., 100000 * 1e18)
lockDurationuint256Duration to lock tokens, measured in intervals (must be ≤ maxLockIntervals)

Returns

  • tokenId - An ERC721 NFT token ID representing your lock position

Token approval: callers must approve the Signals contract for amount on the underlying ERC20 before calling supportInitiative.

Participant Requirements

struct ParticipantRequirements {
    address token;            // Token used for eligibility checks
    uint256 minBalance;         // User must hold this many tokens right now
    uint256 minHoldingDuration; // User must have held tokens for this duration (requires ERC20Votes)
    uint256 minLockAmount;      // Min tokens to lock when supporting (must be ≤ minBalance)
}
Field Descriptions:
  • token: ERC20/IVotes token checked for eligibility (can differ from the underlying lock token).
  • minBalance: User must currently hold this many tokens to be eligible to support
  • minHoldingDuration: User must have held ≥ minBalance tokens for this many blocks in the past. Only works with ERC20Votes tokens that support checkpoints.
  • minLockAmount: Minimum amount user must lock when supporting. Must be equal to or less than minBalance.
Eligibility rules derived from fields:
  • token must be set (cannot be address(0)).
  • minBalance enforces a current balance requirement.
  • minHoldingDuration enforces a historical balance check (requires ERC20Votes checkpoints on token).
  • minLockAmount enforces a minimum lock size and must be ≤ minBalance.

Note: Requires ERC20Votes tokens with checkpoint support for duration-based requirements.

Weight Calculation

Initial Weight Formula

initialWeight = amount * lockDuration

Weight Decay

Linear Decay (Type 0)

weight = lockAmount * lockDuration - (lockAmount * elapsedIntervals * decayRate)
// Floored at lockAmount minimum

Exponential Decay (Type 1)

weight = initialWeight * (decayMultiplier ^ elapsedIntervals)
// Floored at lockAmount minimum

Weight Floor

Weight never drops below the lock amount (nominal value) until the lock expires.

Lock Data Structures

TokenLock

struct TokenLock {
    uint256 initiativeId;     // Which initiative this supports
    address supporter;        // Original supporter address
    uint256 tokenAmount;      // Underlying tokens locked
    uint256 lockDuration;     // Duration in intervals
    uint256 created;          // Block timestamp of creation
    bool withdrawn;           // Redemption status
}

LockData (ISignalsLock interface)

struct LockData {
    uint256 referenceId;      // Initiative ID
    uint256 nominalValue;     // Token amount
    uint256 expires;          // Expiry timestamp
    uint256 created;
    bool claimed;
}

Query Lock Data

  • getTokenLock(tokenId) returns the full lock record.
  • getLockData(tokenId) returns the standardized ISignalsLock view.

Events Emitted

event InitiativeSupported(
    uint256 indexed initiativeId,
    address indexed supporter,
    uint256 tokenAmount,
    uint256 lockDuration,
    uint256 tokenId
)
Event Data:
  • initiativeId: Which initiative was supported
  • supporter: Your address (NFT recipient)
  • tokenAmount: Amount of tokens locked
  • lockDuration: Lock duration in intervals
  • tokenId: ERC721 token ID minted

Validation & Errors

ErrorCauseSolution
Signals_IncorrectBoardStateBoard not openWait for board to open
Signals_InvalidIDInvalid initiative IDUse valid initiative ID
Signals_IncorrectInitiativeStateInitiative not in Proposed stateOnly support Proposed initiatives
Signals_InvalidArgumentsDuration > maxLockIntervalsUse valid duration
Signals_InsufficientTokensBalance < requiredAcquire more tokens
Signals_InsufficientLockAmountAmount < minLockAmountIncrease lock amount
Signals_TokenTransferFailedTransfer failedCheck approval and balance
Signals_InsufficientTokenDurationHaven't held tokens long enoughWait or use different account
Signals_TokenHasNoCheckpointSupportToken doesn't support IVotesBoard misconfigured

Helper Functions

// Get all lock positions for an initiative
function locksForInitiative(uint256 initiativeId) external view returns (uint256[] memory)
 
// Get acceptance threshold
function getAcceptanceThreshold() external view returns (uint256)
 
// Get acceptance criteria
function getAcceptanceCriteria() external view returns (AcceptanceCriteria memory)

Incentive Rewards

If an incentives pool is configured, credits are recorded on lock creation and rewards are paid during redemption after acceptance. The pool does not expose per-supporter previews.