Contracts v1
v1 consists of five contracts plus a few small libraries and hooks. FactoryV1 is the only contract end users interact with directly; everything else is deployed through it.
| FactoryV1 | Single entry point. Orchestrates token creation, pool creation and distribution setup; injects the protocol fee and optional buy-back-and-burn shares. |
| TokenV1 | Minimal ERC20 (OpenZeppelin) that mints fixed initial allocations at construction. |
| TokenV1Factory | Deploys TokenV1 instances and records who requested each one. |
| DistributorV1 | The epoch engine: participation, pro-rata rewards, claiming, drain hooks, allowlists. |
| DistributionV1Factory | Deploys DistributorV1 instances and keeps a list of all distributions for the website. |
TokenV1 & TokenV1Factory
TokenV1 is deliberately boring: a plain OpenZeppelin ERC20 whose constructor mints the entire initial supply to configured allocations. No taxes, no minting later, no owner.
constructor(string memory _name, string memory _symbol, Allocation[] memory _allocations) ERC20(_name, _symbol) {
uint256 totalSupply_ = 0;
for (uint256 i = 0; i < _allocations.length; i++) {
require(_allocations[i].recipient != address(0), "Invalid recipient");
totalSupply_ += _allocations[i].amount;
_mint(_allocations[i].recipient, _allocations[i].amount);
}
require(totalSupply_ > 0, "Total supply must be > 0");
}TokenV1Factory deploys tokens on request and stores the requester per token in creatorOf, so anyone can verify a token was created through the protocol:
tokenAddress = address(new TokenV1(_name, _symbol, _allocations));
creatorOf[tokenAddress] = _creator;
tokenList.push(tokenAddress);
emit NewToken(tokenAddress);DistributorV1
The heart of the protocol — one immutable instance per distribution. All behaviour is fixed at construction via its config:
struct DistributorConfig {
address distributionToken; // token given out to participants
address participationToken; // token received when users participate
uint256 epochDuration; // length of each epoch (seconds)
uint256 startTimestamp; // when epoch 0 begins
uint256 minParticipation; // minimum per-epoch amount
uint256 claimDelaySeconds; // wait after an epoch ends before claiming
bool allowFutureEpochParticipation;
Share[] shares; // where drained epoch funds go
EmissionFunction emissionFunction; // computes each epoch's reward
address allowlistSigner; // address(0) = allowlist disabled
uint256 allowlistDeadline;
uint256 numberOfEpochs;
uint256 totalDistributionAmount;
}Beyond participate and claim (detailed in epoch-based distribution), it exposes batch helpers (participateMany, claimMany) for power users and bots, third-party claim fees (setClaimFeeBps), and read helpers the app uses to render distributions: getContractInfo, getEpochInfo and discoverRewards.
DistributionV1Factory
Deploys distributors and keeps an append-only list so the website can page through every distribution ever created without scanning events:
distributorAddress = address(new DistributorV1(_creator, _config));
creatorOf[distributorAddress] = _creator;
distributionList.push(distributorAddress);
emit NewDistributor(distributorAddress);FactoryV1
The orchestrator. It owns the protocol fee (set by governance), holds references to both sub-factories and hooks, and composes them into one-click flows. The flagship function runs the whole launch:
- Deploys the new token with its allocations.
- Creates the Uniswap V3 pool at the chosen price and adds liquidity — LP tokens are sent to the dead address, locking liquidity forever.
- Injects the buy-back-and-burn share if requested.
- Deploys the distributor and funds it with the full distribution amount of the new token.
tokenAddress = createToken(_tokenName, _tokenSymbol, _tokenAllocations);
_config.distributionToken = tokenAddress;
createPoolAndAddLiquidity(
_config.participationToken, tokenAddress, _sqrtPriceX96,
_participationTokenAmountDesired, _distributionTokenAmountDesired,
false, _participationPermit2, _emptyPermit2()
);
if (_buyBackAndBurnShareBps != 0) _injectBuyAndBurnShare(_config, _buyBackAndBurnShareBps);
distributorAddress = createDistributor(_config, false);SharesLib (basis-point splits validated to sum to 100%), HookLib (approve-and-call plumbing), the three emission curves, and the TransferToHook/BuyAndBurnHookV3 hooks. Full source is on GitHub at sqrtDAO/contracts under src/v1.