Skip to content

feat: add update_campaign_metadata() so business can amend campaign brief before any applications - #38

Merged
JamesVictor-O merged 1 commit into
Ads-Bazaar:mainfrom
iyanumajekodunmi756:feat/update-campaign-metadata
Jul 23, 2026
Merged

feat: add update_campaign_metadata() so business can amend campaign brief before any applications#38
JamesVictor-O merged 1 commit into
Ads-Bazaar:mainfrom
iyanumajekodunmi756:feat/update-campaign-metadata

Conversation

@iyanumajekodunmi756

@iyanumajekodunmi756 iyanumajekodunmi756 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #13

Adds the update_campaign_metadata() function to the campaign-escrow contract, allowing a business to update a campaign's metadata URI (e.g. IPFS brief) before any creator applies. Once a creator applies, the brief is permanently locked to protect applicant trust.

Changes

New functionality

  • update_campaign_metadata() — Updates the metadata_uri field of a campaign. Only the campaign's business may call it.

Rules enforced

Rule Error
Only the campaign's business may call NotCampaignOwner
Rejected on Cancelled or Completed campaigns InvalidStatus
Blocked if any creator has already applied ApplicationsExist
new_metadata must be a non-empty string InvalidMetadata
Blocked while contract is paused ContractPaused

Files changed

File Change
storage.rs Added CampaignApplicants(CampaignId) storage key + add_campaign_applicant() / has_campaign_applicants() helpers
error.rs Added ApplicationsExist = 22 and InvalidMetadata = 23
events.rs Added CampaignMetadataUpdated event
lib.rs Implemented update_campaign_metadata(); wired applicant tracking into apply_to_campaign()
test.rs Added 8 tests in new test_update_metadata module

Tests (8 new)

Test Covers
update_metadata_success Happy path: create → update → verify
update_metadata_after_funding Update allowed while Funded (zero applicants)
not_campaign_owner_cannot_update_metadata Auth guard: stranger gets NotCampaignOwner
applications_exist_blocks_metadata_update Lock: create → apply → try update → ApplicationsExist
empty_metadata_rejected Validation: empty string → InvalidMetadata
cancelled_campaign_rejects_metadata_update Status gate: cancelled → InvalidStatus
completed_campaign_rejects_metadata_update Status gate: completed → InvalidStatus
metadata_not_changed_on_failure Idempotency: failed update leaves original metadata intact
metadata_update_blocked_when_paused Pause gate: paused → ContractPaused

CI

cargo fmt --all -- --check   ✅
cargo clippy --workspace --all-targets -- -D warnings   ✅
cargo test --workspace   ✅ (57 passed, 0 failed)

Design notes

  • Applicant tracking uses a CampaignApplicants persistent storage key (Vec<Address>) that is populated in apply_to_campaign(). This keeps the check O(1) from the contract's perspective without iterating over individual Application storage entries.
  • Status check uses the existing InvalidStatus error on Cancelled/Completed rather than introducing a new CampaignClosed variant, staying consistent with how the rest of the codebase rejects state-changing operations on closed campaigns.
  • The function does not move funds or change campaign status — it is a pure metadata mutation.

closes #13

…rief before any applications

Closes Ads-Bazaar#13

- Added CampaignApplicants storage key and tracking helpers
- Added ApplicationsExist (22) and InvalidMetadata (23) error variants
- Added CampaignMetadataUpdated event
- Wired applicant tracking into apply_to_campaign()
- New function only allows metadata updates when no creator has applied
- Rejects empty metadata strings
- Rejects updates on Cancelled/Completed campaigns
- 8 comprehensive tests covering happy path, auth, pause, and edge cases
@JamesVictor-O
JamesVictor-O merged commit 4fbfb37 into Ads-Bazaar:main Jul 23, 2026
4 checks passed
@JamesVictor-O

JamesVictor-O commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Merged — this one's clean, no follow-up needed. Nice work: the auth/ownership/status checks are correctly ordered, and — worth calling out specifically — the status gate (blocking Cancelled/Completed) isn't actually redundant with the applicant check even though it might look that way at first: a campaign can be cancelled while it still has zero applicants, and the applicant-check alone wouldn't catch an update attempt on that campaign. Good instinct keeping both guards. The 8 tests cover the real edge cases (idempotency-on-failure, paused, both terminal statuses, funded-but-still-zero-applicants) rather than just the happy path.

One non-blocking thought for later: CampaignApplicants stores a full, ever-growing Vec<Address> per campaign, but the only thing read from it is is_empty(). Since applications are already unbounded in this contract (no cap on applicants, only on approved creators via max_creators), a very popular campaign's applicant list will keep growing and getting rewritten on every single application even though nothing after the first one changes the outcome of that check. A bool or u32 counter would give the same guarantee at O(1) storage instead of O(n). Not urgent — just flagging for whenever this contract's storage costs get a real look.

JamesVictor-O pushed a commit that referenced this pull request Jul 25, 2026
…50)

storage::add_campaign_applicant rewrote an ever-growing Vec<Address> on every apply_to_campaign call just to answer a yes/no question in has_campaign_applicants. Replaces it with a u32 counter under DataKey::ApplicantCount, matching the existing approved_count pattern on Campaign, so applying costs O(1) storage-writes regardless of how many creators already applied.

Adds a regression test that applies 200+ creators and asserts (via env.cost_estimate()) that the storage write cost of a later apply matches an early one, plus confirms update_campaign_metadata's lock-after-first-application behavior from #38 is unaffected.

Closes #43

Verified locally in an isolated worktree before merge:
- cargo fmt --all -- --check
- cargo build --workspace
- cargo test --workspace (64 tests)
- cargo clippy --workspace --all-targets -- -D warnings
- cargo build --workspace --target wasm32v1-none --release
- Confirmed via git merge-tree that the merge combines cleanly with #34 and #49, which landed after this branch was cut.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add update_campaign_metadata() so business can amend campaign brief before any applications

2 participants