Skip to main content

POTLOCK Campaigns Contract: Escrow, Targets, and Donations

2025-09-22 · 8 min read

Campaigns contract

Campaigns on POTLOCK let you raise funds for a specific initiative with optional minimum targets and time windows. Donations can be held in escrow until the target is met; otherwise donors are refunded.

PotLock/core11Fork 4

Campaigns contract lives under contracts/ (feat/revised-campaign branch). MIT licensed.

View on GitHub →

Use cases

  • Targeted fundraising for events, projects, or community support.
  • Campaigns on behalf of organizations.
  • Community engagement with clear goals and refunds if target not met.

Types

type CampaignId = u64;
type DonationId = u64;
type TimestampMs = u64;
type ReferrerPayouts = HashMap<AccountId, Balance>;
General types used by the Campaigns contract.

Campaign struct

pub struct Campaign {
    pub owner: AccountId,
    pub name: String,
    pub description: Option<String>,
    pub cover_image_url: Option<String>,
    pub recipient: AccountId,
    pub start_ms: TimestampMs,
    pub end_ms: Option<TimestampMs>,
    pub created_ms: TimestampMs,
    pub ft_id: Option<AccountId>,
    pub target_amount: Balance,
    pub min_amount: Option<Balance>,
    pub max_amount: Option<Balance>,
    pub total_raised_amount: Balance,
    pub net_raised_amount: Balance,
    pub escrow_balance: Balance,
    pub referral_fee_basis_points: u32,
    pub creator_fee_basis_points: u32,
    pub allow_fee_avoidance: bool,
}
Campaign fields: owner, recipient, time window, target/min/max amounts, fees.

Write methods

#[payable]
pub fn create_campaign(
    &mut self,
    name: String,
    description: Option<String>,
    cover_image_url: Option<String>,
    recipient: AccountId,
    start_ms: TimestampMs,
    end_ms: Option<TimestampMs>,
    ft_id: Option<AccountId>,
    target_amount: U128,
    min_amount: Option<U128>,
    max_amount: Option<U128>,
    referral_fee_basis_points: Option<u32>,
    creator_fee_basis_points: Option<u32>,
    allow_fee_avoidance: Option<bool>,
) -> CampaignExternal

#[payable]
pub fn donate(
    &mut self,
    campaign_id: CampaignId,
    message: Option<String>,
    referrer_id: Option<AccountId>,
    bypass_protocol_fee: Option<bool>,
    bypass_creator_fee: Option<bool>,
) -> PromiseOrValue<DonationExternal>
create_campaign and donate. All privileged writes require ≥1 yoctoNEAR attached.

Read methods

pub fn get_config(&self) -> Config
pub fn get_campaign(&self, campaign_id: CampaignId) -> CampaignExternal
pub fn get_campaigns(&self, from_index: Option<u128>, limit: Option<u128>) -> Vec<CampaignExternal>
pub fn get_campaigns_by_owner(&self, owner_id: AccountId, ...) -> Vec<CampaignExternal>
pub fn get_campaigns_by_recipient(&self, recipient_id: AccountId, ...) -> Vec<CampaignExternal>
pub fn get_donations_for_campaign(&self, campaign_id: CampaignId, ...) -> Vec<DonationExternal>
pub fn get_donations_for_donor(&self, donor_id: AccountId, ...) -> Vec<DonationExternal>
Config, campaign by ID, paginated campaigns and donations.

Events

{
  "standard": "potlock",
  "version": "1.0.0",
  "event": "campaign_create",
  "data": [{ "campaign": { ... } }]
}
campaign_create event. set_source_metadata also emitted.

Mainnet: v1.campaigns.potlock.near. Staging: v1.campaigns.staging.potlock.near. Full contract docs: docs.potlock.org/contracts/campaigns-live.