Whitelist Management
SP and branded SP are transfer-restricted by default. Mint, transfer, and redeem flows are gated to addresses on the corresponding allowlist. This makes loyalty supply controllable — only your treasury operators can mint, only authorized addresses can hold the token, only verified counterparties can redeem to collateral.
This guide covers the three allowlists, their contract surface, and a worked example for delegating issuance to a partner without giving them total control.
The Three Allowlists
Each allowlist is gated by its own role. The role you need depends on which allowlist you're modifying.
Mint
MANAGER_ROLE on Factory
Address can call mint paths through the Factory
Transfer
DEFAULT_ADMIN_ROLE on Points
Address can hold and move your branded SP token
Redeem
MANAGER_ROLE on Factory
Address can redeem branded SP back to collateral
MANAGER_ROLE is auto-granted to your deployer wallet at deploy completion (see Prerequisites). DEFAULT_ADMIN_ROLE is held by your deployer wallet by default; migrate to a multisig for production.
Note: pSP issuance is not whitelist-gated. The three allowlists above gate operations on branded SP (Factory + Points contracts). For pSP (PSPVault) there is no separate "mint whitelist"; minting authority comes from one of:
MANAGER_ROLE,ISSUING_ADMIN_ROLE(broad — mint into any active campaign), per-campaign admin status, or a per-campaign delegated minter configuration set viasetMinter(campaignId, minter, limit, active). See the Partner A → Partner B walkthrough below for scoped delegation using the last path.
Same Operation, Three Ways
Every allowlist add/remove can be performed via Studio UI, SDK, or HTTP API. All three paths produce the same on-chain transaction.
Mint
/sp/integrations → Mint Whitelist card → Add to Whitelist → opens "Add Mint Authority" modal
factory.addToMintWhitelist(account)
POST /studio/sdk/v1/tx/whitelist/mint/add
Transfer
/sp/integrations → Transfer Whitelist card → Add to Whitelist → opens "Add Transfer Destination" modal
points.addToTransferWhitelist(account)
POST /studio/sdk/v1/tx/whitelist/transfer/add
Redeem
/sp/integrations → Redeem Whitelist card → Add to Whitelist → opens "Add Redeem Authority" modal
factory.addToRedeemWhitelist(account)
POST /studio/sdk/v1/tx/whitelist/redeem/add
Read paths:
GET /studio/sdk/v1/factory/whitelist/:addressreturns mint and redeem status for an address.points.isTransferWhitelisted(account)returns transfer-allowlist status.
The HTTP API endpoints return an unsigned transaction — the caller signs and broadcasts. This is automation-friendly: any backend, in any language, can drive whitelist operations on testnet or mainnet.
Removing an Address
Symmetric to adding:
Mint
factory.removeFromMintWhitelist(account)
POST /studio/sdk/v1/tx/whitelist/mint/remove
Transfer
points.removeFromTransferWhitelist(account)
POST /studio/sdk/v1/tx/whitelist/transfer/remove
Redeem
factory.removeFromRedeemWhitelist(account)
POST /studio/sdk/v1/tx/whitelist/redeem/remove
Worked Example: Partner A → Partner B Partial Delegation
A real-world scenario from partner setups:
Partner A is the brand owner. Holds
DEFAULT_ADMIN_ROLEand the auto-granted operational roles. Deployed the program. Created Campaign X, which makes them automatically a campaign admin on Campaign X.Partner B is an external partner. Will run reward distribution for Campaign X only.
Partner A wants Partner B to mint pSP into Campaign X up to a fixed budget — and nothing else. Partner B should not be able to mint into other campaigns, create new campaigns, change fees, pause anything, or grant further roles.
The PSPVault supports this directly through per-campaign delegated minters. Partner A configures Partner B as a minter on Campaign X with an explicit limit; Partner B's authority is hard-capped to that one campaign and that one limit. No on-chain role grant is required, and Partner B does not need to be on any Factory whitelist (those gate branded SP, not pSP).
1. Configure Partner B as a Delegated Minter on Campaign X
Partner A calls setMinter(campaignX, partnerB, limit, active=true). This authorises Partner B to call pendingSPVault.mint(campaignX, ...) up to limit total pSP. Once issued >= limit the mint reverts; Partner A can call setMinter again with a new (higher) limit to extend.
The call requires the caller to be either a global MANAGER_ROLE holder or an admin on Campaign X. Partner A satisfies the second condition automatically as the campaign creator.
Studio UI
/campaigns/:id → Authority tab → Configure minter → Partner B's address + limit
SDK
pendingSPVault.setMinter(campaignX, partnerB, limit, true)
HTTP API
POST /studio/sdk/v1/tx/psp/configure-minter with { campaignId, minter, limit, active: true, from }
To pause Partner B's authority without revoking the configuration (e.g., to throttle issuance during an incident), call setMinter(campaignX, partnerB, limit, false). To reactivate, set active=true again.
2. Verify the Partition
Partner A reads back Partner B's minter config to confirm the partition. Partner B should hold no on-chain roles and should appear in the minter table for only Campaign X.
Studio UI
/campaigns/:id → Authority tab — minter table shows Partner B authorised on Campaign X with the configured limit and active=true
Studio UI (alt)
/admin — role roster confirms Partner B holds no on-chain roles
SDK
pendingSPVault.getMinterConfig(campaignX, partnerB) returns { limit, issued, active }
HTTP API
GET /studio/sdk/v1/psp/minter-config/:campaignId/:minter
A negative test confirms scope:
pendingSPVault.createCampaign(...)from Partner B reverts (noMANAGER_ROLEorCAMPAIGN_ADMIN_ROLE).pendingSPVault.mint(campaignY, ...)from Partner B reverts (MinterNotAuthorized— no minter config on Campaign Y).pendingSPVault.mint(campaignX, ...)from Partner B succeeds, up to the configuredlimit.
3. Revoke When the Engagement Ends
Deactivate the minter config:
Studio UI
/campaigns/:id → Authority tab → Deactivate minter
SDK
pendingSPVault.setMinter(campaignX, partnerB, 0, false)
HTTP API
POST /studio/sdk/v1/tx/psp/configure-minter with { campaignId, minter, limit: 0, active: false, from }
Partner B's row in the minter table now shows active=false and Partner B can no longer call mint.
Broader Alternative: Grant ISSUING_ADMIN_ROLE
ISSUING_ADMIN_ROLEIf Partner B needs to mint pSP across any active campaign on this PSPVault (not just Campaign X) — for example, an internal distribution service that drives issuance for every campaign you ever launch — grant ISSUING_ADMIN_ROLE instead. This role lets the holder call mint(...) on any active campaign without per-campaign minter configuration, but the holder is still budget-limited per campaign.
Studio UI
/campaigns/:id → Authority tab → Grant role → ISSUING_ADMIN
SDK
pendingSPVault.grantRole(ISSUING_ADMIN_ROLE, partnerB)
HTTP API
POST /studio/sdk/v1/tx/psp/grant-role with { roleType: 'ISSUING_ADMIN', account: partnerB }
This is a broader grant than the delegated-minter path above. Pick whichever matches the trust level you intend.
When Partner B Also Needs to Mint Branded SP
If the partnership scope expands so Partner B needs to mint branded SP directly — for example, to mint into a custodial wallet — Partner A must additionally add Partner B to the Factory's mint whitelist. Branded SP minting and pSP issuance are gated independently; you can grant one, both, or neither.
Studio UI
/sp/integrations → Mint Whitelist card → Add to Whitelist → "Add Mint Authority" → Partner B's address
SDK
factory.addToMintWhitelist(partnerB)
HTTP API
POST /studio/sdk/v1/tx/whitelist/mint/add with { account: partnerB }
Best Practices
Add partners before they need to interact. Whitelist additions don't propagate instantly; budget time before launch.
Audit allowlists regularly.
/sp/integrationsshows the current state at a glance.Revoke promptly when an engagement ends. Treat allowlist removal and role revocation as part of every off-boarding checklist.
Use distinct addresses per role. Treasury, ops, external partners — keep them on separate wallets so revoking one doesn't disrupt another.
Related
Authority & Roles — full reference for role grants and revokes
Campaigns & Pending SP — what
mint(...)actually does once delegation is set upRoles & Access — the role taxonomy
Last updated