For the complete documentation index, see llms.txt. This page is also available as Markdown.

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.

Allowlist
Required role
What it controls

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 via setMinter(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.

Allowlist
Studio UI
SDK
HTTP API

Mint

/sp/integrationsMint Whitelist card → Add to Whitelist → opens "Add Mint Authority" modal

factory.addToMintWhitelist(account)

POST /studio/sdk/v1/tx/whitelist/mint/add

Transfer

/sp/integrationsTransfer Whitelist card → Add to Whitelist → opens "Add Transfer Destination" modal

points.addToTransferWhitelist(account)

POST /studio/sdk/v1/tx/whitelist/transfer/add

Redeem

/sp/integrationsRedeem 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/:address returns 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:

Allowlist
SDK
HTTP API

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_ROLE and 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.

Path
Where

Studio UI

/campaigns/:idAuthority 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.

Path
Where

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 (no MANAGER_ROLE or CAMPAIGN_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 configured limit.

3. Revoke When the Engagement Ends

Deactivate the minter config:

Path
Where

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

If 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.

Path
Where

Studio UI

/campaigns/:idAuthority 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.

Path
Where

Studio UI

/sp/integrationsMint 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/integrations shows 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.

Last updated