The Cairo NFTFactory deploys receiver.cairo and nft.cairo contracts with deploy_syscall using salt = 0 and fixed constructor calldata. StarkNet computes addresses deterministically from class_hash, salt, constructor_calldata, deploy_from_zero, and caller address. For identical inputs, the derived address is the same. A second deployment to an already‑used address triggers an error that .unwrap_syscall() turns into a revert, producing denial of service for per‑collection receivers and unintentionally coupling multiple collections to one shared receiver. If royalty_fraction = 0, referral usage is recorded but no receiver is deployed, leaving referral payout logic absent.
Vulnerability Details
Using deploy_syscall with salt = 0 and fixed constructor parameters derives a deterministic address. Repeated productions under the same (creator, referral_code, platform, factory) collide, causing unwrap_syscall() to revert and forcing a single shared receiver across distinct NFT collections. This can block per‑collection receivers and break accounting isolation.
StarkNet address derivation uses five inputs: class_hash, salt, constructor_calldata, deploy_from_zero, and caller address when deploy_from_zero = false.
Keeping salt = 0, constructor calldata fixed to [referral_code, creator, platform_address, referral_creator], and factory caller constant derives the same address across productions. A second deployment attempt hits an existing address and reverts at .unwrap_syscall().
Contrast with Solidity V2:
Solidity uses unique salts derived from (name, symbol) and validates address prediction:
Deterministic clone and validation: cloneDeterministic(hashedSalt) with predictDeterministicAddress(...) then require(predicted == actual, RoyaltiesReceiverAddressMismatch())
Attempting to produce multiple collections with the same (creator, referral_code, platform, factory) and royalty_fraction > 0 reuses the receiver’s deterministic address; a second deployment reverts, blocking production.
Operational disruption: teams cannot deploy a new per‑collection receiver when needed; CI or scripts looping production may repeatedly fail.
Unintended receiver sharing across collections:
Distinct collections inadvertently share one receiver instance, breaking desired per‑collection isolation, access control, upgradability independence, and auditability.
Accounting inconsistencies and fee routing issues:
Referral usage is recorded in the factory even when royalty_fraction = 0, but no receiver exists to handle referral splits for secondary royalties; without a clear payout path, referral share accounting can be missing or inconsistent.
Global referral “times used” increments: producing new collections can elevate the referral tier globally, unintentionally increasing referral share for all existing and future collections under the same (creator, code) context. This can divert platform fees unexpectedly.
References
Cairo source:
src/nftfactory/nftfactory.cairo (receiver deploy and referral usage)
_set_referral_user(...) and receiver deploy
NFT deploy
Referral usage logic
src/receiver/receiver.cairo: payout shares and referral split handling