Summary
The rewards contract supports campaign multipliers via campaign_multiplier(campaign_id), but the campaign_id is a u64 with no on-chain linkage to an actual campaign contract address. This loose coupling means any caller can claim any campaign_id multiplier without proving they are associated with that campaign.
Problem
In contracts/rewards/src/lib.rs:159:
pub fn campaign_multiplier(env: Env, campaign_id: u64) -> u32 {
campaign_id is arbitrary; there is no validation that it corresponds to a real deployed campaign
- A caller could abuse a high-multiplier campaign_id to credit themselves at an inflated rate
- No on-chain record linking campaign contract address ↔ campaign_id
Acceptance Criteria
References
contracts/rewards/src/lib.rs:139-165
contracts/campaign/src/lib.rs:339 — is_active()
Summary
The rewards contract supports campaign multipliers via
campaign_multiplier(campaign_id), but the campaign_id is au64with no on-chain linkage to an actual campaign contract address. This loose coupling means any caller can claim any campaign_id multiplier without proving they are associated with that campaign.Problem
In
contracts/rewards/src/lib.rs:159:campaign_idis arbitrary; there is no validation that it corresponds to a real deployed campaignAcceptance Criteria
campaign_idtype fromu64toAddress(the actual campaign contract address)set_campaign_multiplier(admin, campaign_contract: Address, multiplier_bps)now takes an Addresscredit_for_campaign(from, user, campaign_contract: Address, base_amount)— validate thatcampaign_contract.is_active()returns true before applying multiplier (cross-contract read)frontend/src/stellar.jsaccordinglyCHANGELOG.md(breaking change in campaign_id type)References
contracts/rewards/src/lib.rs:139-165contracts/campaign/src/lib.rs:339—is_active()