Problem
create_campaign accepts an arbitrary PayoutAsset { token: Address, symbol: String } with no validation that token is actually a deployed, spendable SEP-41 token contract. The first time it's ever touched is fund_campaign's token::Client::transfer call — meaning a business can create a campaign (and, worse, get creators to apply/get approved/submit proof against it) against a token address that turns out to be a non-contract address, a contract that doesn't implement the token interface, or a token that behaves unexpectedly, and nobody finds out until funding time or later.
This is a "fails safe, but fails late" problem rather than an exploitable bug — every money-moving call already goes through the real token contract's transfer, so a bad token address can't drain anything, it just wastes everyone's time (business, creators) building up a campaign that can never actually be funded, or funds unexpectedly.
Expected behaviour
At create_campaign time, do a lightweight sanity check that asset.token is a real, responsive token contract — e.g. calling a cheap read-only method like token::Client::new(&env, &asset.token).decimals() and propagating a clear error (Error::InvalidAsset or similar) if the call fails/traps, rather than letting a bad address silently sail through to fund_campaign or later.
Worth deciding whether this should be a hard requirement or best-effort (Soroban's cross-contract call failure semantics for a call to an address that isn't a contract at all are worth checking against the current SDK version before committing to the exact mechanism).
Files
contracts/campaign-escrow/src/lib.rs — create_campaign
contracts/campaign-escrow/src/error.rs — new error variant
Acceptance criteria
Problem
create_campaignaccepts an arbitraryPayoutAsset { token: Address, symbol: String }with no validation thattokenis actually a deployed, spendable SEP-41 token contract. The first time it's ever touched isfund_campaign'stoken::Client::transfercall — meaning a business can create a campaign (and, worse, get creators to apply/get approved/submit proof against it) against a token address that turns out to be a non-contract address, a contract that doesn't implement the token interface, or a token that behaves unexpectedly, and nobody finds out until funding time or later.This is a "fails safe, but fails late" problem rather than an exploitable bug — every money-moving call already goes through the real token contract's
transfer, so a bad token address can't drain anything, it just wastes everyone's time (business, creators) building up a campaign that can never actually be funded, or funds unexpectedly.Expected behaviour
At
create_campaigntime, do a lightweight sanity check thatasset.tokenis a real, responsive token contract — e.g. calling a cheap read-only method liketoken::Client::new(&env, &asset.token).decimals()and propagating a clear error (Error::InvalidAssetor similar) if the call fails/traps, rather than letting a bad address silently sail through tofund_campaignor later.Worth deciding whether this should be a hard requirement or best-effort (Soroban's cross-contract call failure semantics for a call to an address that isn't a contract at all are worth checking against the current SDK version before committing to the exact mechanism).
Files
contracts/campaign-escrow/src/lib.rs—create_campaigncontracts/campaign-escrow/src/error.rs— new error variantAcceptance criteria
create_campaignrejects atokenaddress that isn't a real, responsive SEP-41 contractfund_campaign