starling
Reference

The contract

One file, contracts/src/Flock.sol, Solidity 0.8.26. No owner, no admin, no proxy, no fee of ours. The only external dependencies are the Pons factory (address fixed at deployment) and the curve it creates.

Constants

namevaluemeaning
MAX_SIZE0.25 ETHlargest buy a flock can make
COMMIT_MULTIPLE100deposits may reach 100 × size
MIN_DEPOSIT0.001 ETHsmallest deposit, smallest minimum and per-wallet cap
MAX_TAX_BPS500creator tax a flock may carry (Pons allows 1000)
MIN_WINDOW / MAX_WINDOW5 minutes / 7 daysdistance between open and the deadline
GRACE1 dayafter the deadline, anybody can still launch; then it is refundable

State

struct Info {
  address creator; State state;      // Open, Launched, Cancelled
  uint64 deadline; uint96 minTotal; uint96 size; uint96 maxPerWallet;
  uint128 total; uint128 used; uint128 reserve;
  uint256 launchConfigId; uint256 minTokensPerEth;
  bytes32 paramsHash; address token; address curve; uint256 tokensOut; uint128 reserveLeft;
}
mapping(uint256 => Info) public flocks;
mapping(uint256 => mapping(address => uint256)) public deposits;
uint256 public count;

Functions

functionwhowhat
open(params, terms) payableanyonestores the terms and the params hash, emits Opened with the params; msg.value ≥ Pons launch fee is the reserve
join(id) payableanyonedeposit before the deadline; bounded by the per-wallet cap and 100 × size
leave(id)depositorfull refund before the deadline
launch(id, params)anyoneafter the deadline, within the grace: creates the token and buys min(total, size)
claim(id) / claimFor(id, who[])depositor / anyonetokens and refund for each depositor; tokens only go to the depositor
cancel(id)creatorbefore the deadline
refund(id)depositorwhen the flock failed or was cancelled
reclaim(id)creatorfee reserve back (all of it if failed, the unused part if launched)
failed(id), shareOf(id, who)viewstatus, and the (tokens, refund) a depositor would receive

What launch does, in order

  1. checks the state, the deadline, the grace, the minimum and the params hash
  2. reads the Pons launch fee and checks the reserve covers it
  3. computes used, sets the state to Launched before any external call
  4. calls factory.launchToken with itself as snipe-tax exemption
  5. calls curve.buy(used, minOut, this)
  6. reads its own balance of the new token and checks it against the floor (PriceFloor)
  7. stores the token, the curve and the tokens bought

Events

Opened(uint256 indexed id, address indexed creator, bytes32 paramsHash, Terms terms, bytes encodedParams)
Joined(id, who, amount, total)        Left(id, who, amount, total)
Launched(id, token, curve, total, used, tokensOut)
Claimed(id, who, tokens, refund)      Refunded(id, who, amount)      Cancelled(id)

Errors

errormeaning
BadTerms / BadParamsterms or params outside the allowed range, or launch params that do not match the hash
NotOpen / TooEarly / TooLate / Closedwrong state or wrong moment; Closed = past the grace or below the minimum
OverCap / TooSmalldeposit above a cap or below 0.001 ETH
NotCreator / NotFailed / NothingToDocaller, status or balance does not allow it
FeeNotCoveredthe creator's reserve is below the Pons launch fee
PriceFloorthe buy gave fewer tokens than minTokensPerEth
SendFailed / Reentrancyan ETH or token transfer failed; a re-entrant call was refused