Campaigns & Pending SP
This guide walks through the operational lifecycle of a pSP campaign: create, issue, settle, clawback, recycle. For the conceptual model — why pSP exists, how budget recycling works — see Pending SP (pSP).
Lifecycle Mental Model
SP is the stable currency. pSP is conditional escrow.
You create a campaign with an SP budget.
You issue pSP to users.
Users that meet the campaign condition (hold N days, perform action X) get their pSP settled into SP and delivered to a destination address.
For pSP that goes unfulfilled, an admin explicitly clawbacks the balance back into the campaign budget. pSP does not auto-expire — it stays in the user's balance until an admin acts on it.
Each step is gated by a specific role. The role model lets you split operations across teams or partners — see Whitelist Management → Partner A → Partner B for the canonical delegation example.
Create a Campaign
Required authority: MANAGER_ROLE or CAMPAIGN_ADMIN_ROLE on the PSPVault. CAMPAIGN_ADMIN_ROLE is auto-granted to your deployer wallet. The caller automatically becomes a per-campaign admin on the campaign they create (which lets them later configure delegated minters and per-campaign whitelists without needing additional grants).
The on-chain createCampaign call takes:
createCampaign(
bytes32 campaignId,
uint256 spBudget,
address[] settlementDestinations,
address[] transferWhitelist,
string metadata
)Studio UI
/sp/pending → New campaign
SDK
pendingSPVault.createCampaign(campaignId, spBudget, settlementDestinations, transferWhitelist, metadata)
HTTP API
POST /studio/sdk/v1/tx/psp/create-campaign
spBudget must be funded — you transfer SP into the vault before or as part of campaign creation. Use pendingSPVault.fundCampaign(campaignId, amount) (HTTP: POST /studio/sdk/v1/tx/psp/fund-campaign) to top up an existing campaign.
Issue pSP
Authority to call mint(...) comes from any of:
MANAGER_ROLEon the PSPVault (no per-campaign limit, no budget limit beyond the campaign'sspBudget).ISSUING_ADMIN_ROLEon the PSPVault — broad: the holder can mint into any active campaign on this vault, budget-limited only.Campaign admin status on a specific campaign — the campaign creator gets this automatically; additional admins can be added with
setCampaignAdmin.A per-campaign delegated minter configuration set via
setMinter(campaignId, minter, limit, active=true)— scoped to one campaign with a hard limit. See Whitelist Management → Partner A → Partner B for the canonical scoped-delegation pattern.
Studio UI
Campaign detail → Issue pSP
SDK
pendingSPVault.mint(campaignId, to, amount, metadata)
HTTP API
POST /studio/sdk/v1/tx/psp/mint
Issuance is the high-frequency operation in a campaign. Most partners drive it from a backend service that watches user activity and calls mint(...) server-side via the SDK or HTTP API.
Settle pSP → SP
Required role: SETTLEMENT_ADMIN_ROLE. The destination must be on the campaign's settlement whitelist (see updateSettlementWhitelist).
Studio UI
Campaign detail → Settle
SDK
pendingSPVault.settle(holder, receiver, amount, campaignId, metadata)
HTTP API
POST /studio/sdk/v1/tx/psp/settle
Settlement converts pSP into SP and delivers it to the receiver address. Use the same address as the holder for direct claims, or a different address for redirect (e.g., to a custodian).
Clawback Unfulfilled pSP
pSP does not auto-expire. Issued pSP stays in a user's balance indefinitely until an admin explicitly settles it (converts to SP, sends to a destination) or clawbacks it (returns the underlying SP to the campaign budget).
To clawback unfulfilled pSP — typically at the end of a campaign window or for a user that didn't meet the qualifying condition — an admin calls expire(...):
Studio UI
Campaign detail → Clawback / Expire
SDK
pendingSPVault.expire(holder, amount, campaignId, metadata)
HTTP API
POST /studio/sdk/v1/tx/psp/expire
The clawed-back SP returns to the campaign budget. You can then issue new pSP from the recycled budget without depositing additional collateral.
Required role: SETTLEMENT_ADMIN_ROLE.
Per-Campaign Whitelists
Each campaign has its own settlement-destination whitelist (which addresses can receive settled SP) and transfer whitelist (which addresses can hold pSP for this campaign). Both are set at createCampaign time and can be amended afterward:
Update settlement whitelist
pendingSPVault.updateSettlementWhitelist(campaignId, account, allowed)
POST /studio/sdk/v1/tx/psp/update-settlement-whitelist
Update transfer whitelist
pendingSPVault.updateTransferWhitelist(campaignId, account, allowed)
POST /studio/sdk/v1/tx/psp/update-transfer-whitelist
These per-campaign whitelists are independent of mint authorisation, which comes from ISSUING_ADMIN_ROLE, per-campaign admin status, or a per-campaign delegated-minter config (setMinter). See the worked example in Whitelist Management for how to scope all three.
Required Roles by Step
Create campaign
MANAGER_ROLE or CAMPAIGN_ADMIN_ROLE (creator becomes per-campaign admin automatically)
Configure per-campaign minter / settlement / transfer whitelist
MANAGER_ROLE or per-campaign admin
Set additional campaign admins
MANAGER_ROLE or campaign creator
Issue pSP
One of: MANAGER_ROLE, ISSUING_ADMIN_ROLE, per-campaign admin, or active per-campaign delegated minter
Settle pSP → SP
MANAGER_ROLE or SETTLEMENT_ADMIN_ROLE
Clawback / expire
MANAGER_ROLE or SETTLEMENT_ADMIN_ROLE
Admin transfer between users
MANAGER_ROLE or TRANSFER_ADMIN_ROLE
Common Patterns
Hold-and-release
Hold ≥ X SP for N days
User completes a target action
Hold duration validated on-chain
Swap-and-claim
Complete N swaps
User performs first swap
Nth swap confirmed
Event attendance
Attend N events
Pre-event registration
Attendance check-in
Spend-and-earn
Spend ≥ $X
Purchase confirmation
Refund window passes
Related
Authority & Roles — delegating campaign roles
Whitelist Management — the Partner A → Partner B walkthrough composes
ISSUING_ADMIN_ROLEwith per-campaignsetMinterfor scoped delegation
Last updated