Crowdfund
Backers pledge ether before a deadline. If the goal is reached, the creator claims everything. Otherwise each backer takes back their own pledge.
crowdfund.lithe
(* Pledge ether toward a goal before a deadline. If the goal is met, the creator
claims the funds. If not, each backer takes their pledge back. *)
import "std/address";
import "std/evm";
error AlreadyStarted;
error Ended;
error NotEnded;
error GoalNotMet;
error GoalMet;
error NotCreator;
error AlreadyClaimed;
error NothingPledged;
event Pledged of record {
indexed backer : address;
amount : wei;
}
storage is record {
creator : address;
goal : wei;
deadline : timestamp;
raised : wei;
claimed : bool;
pledges : map(address, wei);
}
external function launch(const goal : wei; const duration : uint)
raises AlreadyStarted
is {
assert(storage.creator = Address.zero, AlreadyStarted);
storage.creator := Evm.sender();
storage.goal := goal;
storage.deadline := Evm.blockTimestamp() + duration;
}
external payable function pledge()
raises Ended
is {
assert(Evm.blockTimestamp() < storage.deadline, Ended);
storage.pledges[Evm.sender()] := storage.pledges[Evm.sender()] + Evm.value();
storage.raised := storage.raised + Evm.value();
emit Pledged { backer = Evm.sender(); amount = Evm.value(); };
}
external nonreentrant function claim()
raises NotCreator | NotEnded | GoalNotMet | AlreadyClaimed
is {
assert(Evm.sender() = storage.creator, NotCreator);
assert(Evm.blockTimestamp() >= storage.deadline, NotEnded);
assert(storage.raised >= storage.goal, GoalNotMet);
assert(not storage.claimed, AlreadyClaimed);
storage.claimed := true;
defer Evm.transfer(storage.creator, storage.raised);
}
external nonreentrant function refund()
raises NotEnded | GoalMet | NothingPledged
is {
assert(Evm.blockTimestamp() >= storage.deadline, NotEnded);
assert(storage.raised < storage.goal, GoalMet);
const amount : wei := storage.pledges[Evm.sender()];
assert(amount > 0wei, NothingPledged);
storage.pledges[Evm.sender()] := 0wei;
defer Evm.transfer(Evm.sender(), amount);
}
