Skip to content

[LOW] donate fetches donor record twice; first read is discarded #81

Description

@Alqku

Summary

campaign/src/lib.rs::donate reads the donor record from storage twice in immediate succession. The first read is bound to _donor_record and immediately discarded; the second read binds to existing_donor which is the one actually used (and re-fetched into mut donor_record).

Location

campaign/src/lib.rs, around lines 162–170 (inside pub fn donate(...)):

let _donor_record =
    get_donor(&env, &donor).unwrap_or(DonorRecord::new_for(donor.clone(), asset.clone()));
// Update donor record
let existing_donor = get_donor(&env, &donor);
let is_new_donor = existing_donor.is_none();
let mut donor_record =
    existing_donor.unwrap_or_else(|| DonorRecord::new_for(donor.clone(), asset.clone()));

Impact

  • Wasted host storage calls: Three separate calls to get_donor (the third is implicit via unwrap_or_else if the record is missing), each one reading persistent storage and bumping the donor-record TTL via bump_persistent. On a hot donation path this is pure overhead.
  • Allocates an unused DonorRecord: DonorRecord::new_for(donor.clone(), asset.clone()) is constructed for the discarded read — cloning the Address and AssetInfo for nothing.
  • Aesthetics: The code visually suggests the contract behaves differently depending on the first read, when in fact only the second and third matter.

The same pattern (read-once-discard, read-again) exists in claim_refund (separate issue, see [follow-up link once created]).

Fix

Delete the leading _donor_record line entirely; the rest of the block already does the right thing:

let existing_donor = get_donor(&env, &donor);
let is_new_donor = existing_donor.is_none();
let mut donor_record =
    existing_donor.unwrap_or_else(|| DonorRecord::new_for(donor.clone(), asset.clone()));

Severity

[LOW] — dead code, no security or correctness impact. It just inflates the per-donation host-cost and confuses readers about which value is being honoured.

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignCampaign: Official Campaign

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions