Skip to main content

Perk Effects System

The Perk Effects System allows any perk to carry configurable effects that activate when claimed. Effects can multiply earnings, protect streaks, grant raffle entries, award badges, and assign Discord roles.

Key principle: Effects are brand-deployable. Any brand can create perks with effects through the Partner Portal — no developer assistance needed.

How It Works​

1. Brand creates a perk in the Partner Portal PerkWizard
2. Brand enables one or more effects (checkboxes) and configures values
3. Perk is published to the marketplace with effect metadata
4. User claims the perk (burns RSNC, receives NFT)
5. Post-claim hook creates activation records in the database
6. Bot checks activation records during reward calculation
7. Effects are applied: multiplied earnings, protected streaks, etc.

Effect Types​

EffectWhat It DoesDurationStacking
Earning MultiplierMultiplies RSNC earned per reward event7 days (configurable)Replace (latest wins)
Event Cap BoostIncreases daily event claim limits for count-based events7 days (configurable)Replace (latest wins)
Streak ShieldPrevents streak reset when a day is missed7-day shelf lifeAccumulate (up to 5 charges)
Raffle EntryGrants entries into a weekly raffle drawingInstantAccumulate (up to 15/week)
Profile BadgePermanent cosmetic badge on user profilePermanentCollect (own multiple)
Discord RoleGrants a Discord role when claimedPermanent or durationCollect

Creating a Perk with Effects​

In the Partner Portal​

  1. Open the PerkWizard (Create Perk)
  2. Fill in basic info (name, description, price, supply)
  3. Scroll to the Perk Effects section
  4. Check the effects you want this perk to have
  5. Configure the values for each enabled effect
  6. Set the Effect Scope (where effects apply)
  7. Review and publish

Effect Scope​

Effects can apply beyond the creating brand's servers:

ScopeBehavior
Own Brand (default)Effects only apply in the creating brand's servers
Selected PartnersEffects apply in the creating brand's servers + named partner brands
NetworkEffects apply across all Resonance servers (admin-only)

Cross-brand consent required: For "Selected Partners" scope, each partner brand must explicitly accept external effects via the Brand Consent settings in their Partner Portal.

Effect Metadata​

Effects are stored in the perk's metadata as a JSON array:

{
"effects": [
{
"type": "earning_multiplier",
"value": { "multiplier": 2.75 },
"duration_days": 7,
"stacking": "replace",
"scope": { "type": "own_brand" },
"max_active_per_user": 1
},
{
"type": "streak_shield",
"value": { "charges": 3 },
"duration_days": 7,
"stacking": "accumulate",
"scope": { "type": "own_brand" },
"max_active_per_user": 5
}
]
}

Effect Resolution​

When the bot calculates a reward, the PerkEffectEngine resolves active effects through a 7-step pipeline:

  1. Cache check — KV cache lookup (5-min TTL)
  2. Fetch activations — Query perk_effect_activations for user
  3. Scope filter — Does this effect apply in the current brand context?
  4. Consent filter — Does the current brand accept effects from the source brand?
  5. Group by type — Organize effects by effect_type
  6. Apply stacking — Replace (latest wins), accumulate (sum with cap), highest, or collect
  7. Cache result — Store resolved set in KV

Reward Calculation Chain​

final_reward = base_reward
x role_multiplier (from Discord role config)
x perk_earning_multiplier (from active Amplifier effect)
+ flat_bonus (from role config)
x streak_multiplier (from streak days)

The combined role_multiplier x perk_earning_multiplier is capped at 10x (security limit).

API Reference​

All endpoints require internal authentication (CF-Worker header or X-Internal-Secret).

Resolve Effects​

GET /perk-effects/:brandId/:userIdentifier

Returns the resolved effect set for a user in a brand context.

Response:

{
"earning_multiplier": { "multiplier": 2.75 },
"event_cap_multiplier": null,
"streak_shield": { "charges": 3 },
"badges": [{ "badge_id": "signal_carrier", "badge_tier": "standard" }],
"role_grants": []
}

Activate Effects​

POST /perk-effects/activate

Called after a perk claim to create activation records.

Body:

{
"user_identifier": "discord:123456789",
"source_brand_id": "0xBrandAddress",
"collection_id": 42,
"effects": [
{
"type": "earning_multiplier",
"value": { "multiplier": 1.5 },
"duration_days": 7,
"scope": { "type": "own_brand" }
}
]
}

Consume Shield Charge​

POST /perk-effects/consume-shield

Atomically consumes one streak shield charge.

Body:

{
"user_identifier": "discord:123456789",
"context_brand_id": "0xBrandAddress"
}

Response:

{
"consumed": true,
"chargesRemaining": 2
}

Cleanup Expired Effects​

POST /perk-effects/cleanup

Deactivates expired effects. Called by scheduled CRON.

GET /brand-consent/:brandId
POST /brand-consent/:brandId

Body:

{
"source_brand_id": "0xStartaleAddress",
"allowed_effect_types": ["earning_multiplier", "badge"],
"max_multiplier": 3.0
}
DELETE /brand-consent/:brandId/:sourceBrandId

Raffle API​

Add Entries​

POST /raffle/enter

Body:

{
"brand_id": "0xBrandAddress",
"user_identifier": "discord:123456789",
"collection_id": 42,
"entry_count": 5,
"rsnc_spent": 400
}

Get Draw Pool​

GET /raffle/pool/:brandId/:drawWeek

Execute Draw​

POST /raffle/draw

Body:

{
"brand_id": "0xBrandAddress",
"draw_week": "2026-W14",
"prize_config": {
"type": "rsnc_pot",
"winner_share": 0.7,
"burn_share": 0.3
}
}

Security​

Validation Limits​

EffectMax ValueEnforced At
Earning Multiplier5.0x per perkPerkWizard + post-claim hook
Event Cap Multiplier3.0x per perkPerkWizard + post-claim hook
Streak Shield5 charges maxPerkWizard + activation logic
Raffle Entries15 per purchase, 15 per weekPerkWizard + entry logic
Combined Multiplier10x (role + perk)Bot reward calculation

Brand Isolation​

  • Effects are scoped by source_brand_id and effect_scope
  • Cross-brand effects require explicit consent via brand_effect_consent
  • Consent can cap multiplier values independently
  • The brandId used for resolution comes from trusted server config, not user input

Deduplication​

A unique index prevents duplicate active effects from the same collection:

UNIQUE(user_identifier, collection_id, effect_type) WHERE is_active = true

Re-claiming the same perk replaces (UPSERT) rather than stacking.

Database Tables​

perk_effect_activations​

Core table tracking active effects per user.

ColumnTypeDescription
source_brand_idTEXTBrand that created the perk
collection_idBIGINTPerk collection ID
user_identifierTEXTdiscord:{userId}
effect_typeTEXTRegistry key
effect_valueJSONBType-specific payload
effect_scopeJSONBWhere the effect applies
expires_atTIMESTAMPTZNULL for permanent effects
charges_remainingINTFor consumable effects
is_activeBOOLEANDeactivated on expiry/consumption

Cross-brand effect acceptance.

ColumnTypeDescription
brand_idTEXTBrand accepting effects
source_brand_idTEXTBrand whose effects are accepted
allowed_effect_typesTEXT[]NULL = all types
max_multiplierNUMERICSafety cap on multiplier values

raffle_entries / raffle_draws​

Weekly raffle system tables. See Raffle API for details.