Skip to content
LogoLogo

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);
}