# 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)](/spreefinance/products/pending-sp.md).

## Lifecycle Mental Model

SP is the stable currency. pSP is conditional escrow.

1. You create a campaign with an SP budget.
2. You issue pSP to users.
3. Users that meet the campaign condition (hold N days, perform action X) get their pSP **settled** into SP and delivered to a destination address.
4. 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](/spreefinance/spree-studio/whitelist-management.md#worked-example-partner-a--partner-b-partial-delegation) 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:

```solidity
createCampaign(
  bytes32 campaignId,
  uint256 spBudget,
  address[] settlementDestinations,
  address[] transferWhitelist,
  string metadata
)
```

| Path      | Where                                                                                                      |
| --------- | ---------------------------------------------------------------------------------------------------------- |
| 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_ROLE` on the PSPVault (no per-campaign limit, no budget limit beyond the campaign's `spBudget`).
* `ISSUING_ADMIN_ROLE` on 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](/spreefinance/spree-studio/whitelist-management.md#worked-example-partner-a--partner-b-partial-delegation) for the canonical scoped-delegation pattern.

| Path      | Where                                                   |
| --------- | ------------------------------------------------------- |
| 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`](#per-campaign-whitelists)).

| Path      | Where                                                                   |
| --------- | ----------------------------------------------------------------------- |
| 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(...)`:

| Path      | Where                                                         |
| --------- | ------------------------------------------------------------- |
| 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:

| Operation                   | SDK                                                                      | HTTP API                                                 |
| --------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------- |
| 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](/spreefinance/spree-studio/whitelist-management.md#worked-example-partner-a--partner-b-partial-delegation) for how to scope all three.

## Required Roles by Step

| Step                                                            | Authority required                                                                                        |
| --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| 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

| Pattern          | Condition              | Issue when                     | Settle when                      |
| ---------------- | ---------------------- | ------------------------------ | -------------------------------- |
| 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

* [Pending SP (pSP) concepts](/spreefinance/products/pending-sp.md)
* [Authority & Roles](/spreefinance/spree-studio/authority-and-roles.md) — delegating campaign roles
* [Whitelist Management](/spreefinance/spree-studio/whitelist-management.md) — the Partner A → Partner B walkthrough composes `ISSUING_ADMIN_ROLE` with per-campaign `setMinter` for scoped delegation


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://spree-finance.gitbook.io/spreefinance/spree-studio/campaigns-and-pending-sp.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
