> For the complete documentation index, see [llms.txt](https://spree-finance.gitbook.io/spreefinance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://spree-finance.gitbook.io/spreefinance/developer-guides/stable-points-sp/campaign-operations.md).

# Campaign & pSP Operations

Pending SP (pSP) is an escrowed reward token. Brands create campaigns, fund them with SP, and distribute pSP to users. pSP converts to SP after users meet conditions (settlement). Unfulfilled pSP recycles back to the brand's budget.

### Campaign Lifecycle

1. **Create** a campaign with supply caps and parameters
2. **Fund** the campaign with SP tokens
3. **Activate** the campaign
4. **Mint** pSP to users (or mintBoosted for boost-eligible mints)
5. **Settle** pSP to convert to real SP
6. **Expire** unclaimed pSP (recycles budget)

### Create a Campaign

```typescript
import { PendingSPVault } from '@spree-finance/spree-evm-sdk';

const psp = new PendingSPVault({
  rpcUrl: 'https://sepolia.base.org',
  chainId: 84532n,
  contractAddress: '0xPendingSPVaultAddress',
  from: '0xYourWallet',
  defaultGasPriceWei: 1_000_000_000n,
  defaultGasLimit: 500_000n,
});

const createTx = await psp.createCampaign(
  'Summer Rewards 2025',                    // name
  '0xCampaignAdmin',                        // admin address
  1_000_000_000_000_000_000_000n,           // maxTotalSupply: 1000 pSP
  100_000_000_000_000_000_000n,             // maxMintPerUser: 100 pSP per user
  10_000_000_000_000_000_000n,              // dailyMintLimit: 10 pSP per day
  Math.floor(Date.now() / 1000) + 86400,   // startTime: tomorrow
  Math.floor(Date.now() / 1000) + 2592000, // endTime: 30 days from now
  604800n,                                  // vestingPeriod: 7 days (seconds)
);
```

#### Supply Caps

| Parameter        | Purpose                                   |
| ---------------- | ----------------------------------------- |
| `maxTotalSupply` | Total pSP the campaign can ever mint      |
| `maxMintPerUser` | Per-user cap across the campaign lifetime |
| `dailyMintLimit` | Per-user cap per calendar day             |

### Fund a Campaign

Transfer SP into the campaign's budget:

```typescript
const fundTx = await psp.fundCampaign(
  1n,                                        // campaignId
  500_000_000_000_000_000_000n,              // amount: 500 SP
);
```

### Activate a Campaign

```typescript
const activateTx = await psp.setCampaignActive(1n, true);
```

### Set Minter

Grant an address permission to mint pSP for this campaign:

```typescript
const setMinterTx = await psp.setMinter(1n, '0xMinterAddress', true);
```

### Mint pSP to Users

```typescript
// Standard mint
const mintTx = await psp.mint(
  1n,                             // campaignId
  '0xUserAddress',                // recipient
  50_000_000_000_000_000_000n,    // amount: 50 pSP
);

// Boosted mint (applies boost multiplier from BoostEngine)
const boostedTx = await psp.mintBoosted(
  1n,                             // campaignId
  '0xUserAddress',                // recipient
  50_000_000_000_000_000_000n,    // baseAmount: 50 pSP (boost applied on top)
);
```

### Settle pSP

Convert pSP to real SP after vesting conditions are met. Fee: 20 bps on finalization.

```typescript
const settleTx = await psp.settle(
  1n,              // campaignId
  '0xUserAddress', // user whose pSP to settle
);
```

### Expire Unclaimed pSP

Recycle unfulfilled pSP back to the campaign budget:

```typescript
const expireTx = await psp.expire(
  1n,              // campaignId
  '0xUserAddress', // user whose pSP to expire
);
```

### Transfer pSP Between Users

```typescript
const transferTx = await psp.transferWithCampaign(
  1n,              // campaignId
  '0xFrom',        // sender
  '0xTo',          // recipient
  25_000_000_000_000_000_000n, // amount
);
```

### Set Campaign Admin

```typescript
const adminTx = await psp.setCampaignAdmin(1n, '0xNewAdmin');
```

### Read Campaign State

```typescript
// Get full campaign details
const campaign = await psp.readGetCampaign(1n);

// User's pSP balance in a campaign
const userBalance = await psp.readBalanceOfCampaign(1n, '0xUserAddress');

// Remaining mintable budget
const available = await psp.readGetCampaignAvailableBudget(1n);

// All campaigns a user participates in
const userCampaigns = await psp.readGetUserCampaigns('0xUserAddress');
```

### Full Workflow Example

```typescript
import { PendingSPVault } from '@spree-finance/spree-evm-sdk';

const psp = new PendingSPVault(config);

// 1. Create campaign
const createTx = await psp.createCampaign(
  'Launch Promo',
  '0xAdmin',
  10_000_000_000_000_000_000_000n,  // 10,000 max supply
  500_000_000_000_000_000_000n,     // 500 per user
  50_000_000_000_000_000_000n,      // 50 daily limit
  startTimestamp,
  endTimestamp,
  604800n,  // 7 day vesting
);
// Sign and broadcast createTx...

// 2. Fund it
const fundTx = await psp.fundCampaign(1n, 5_000_000_000_000_000_000_000n);
// Sign and broadcast...

// 3. Activate
const activateTx = await psp.setCampaignActive(1n, true);
// Sign and broadcast...

// 4. Grant minter role
const minterTx = await psp.setMinter(1n, '0xBackendSigner', true);
// Sign and broadcast...

// 5. Mint to user
const mintTx = await psp.mint(1n, '0xUser', 100_000_000_000_000_000_000n);
// Sign and broadcast...

// 6. After vesting period, settle
const settleTx = await psp.settle(1n, '0xUser');
// Sign and broadcast...
```
