sqrtDAO docs

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.

Creator & userssingle transactionFactoryV1entry pointTokenV1FactoryTokenV1ERC20 with allocationsDistributionV1FactoryDistributorV1users participate & claimcreates pool · LP burnedUniswap V3 pool0.3% fee tiershares (bps)TransferToHookBuyAndBurnHookV3
v1 architecture: FactoryV1 orchestrates the sub-factories, distributor and hooks
FactoryV1Single entry point. Orchestrates token creation, pool creation and distribution setup; injects the protocol fee and optional buy-back-and-burn shares.
TokenV1Minimal ERC20 (OpenZeppelin) that mints fixed initial allocations at construction.
TokenV1FactoryDeploys TokenV1 instances and records who requested each one.
DistributorV1The epoch engine: participation, pro-rata rewards, claiming, drain hooks, allowlists.
DistributionV1FactoryDeploys 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.

TokenV1.sol
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:

TokenV1Factory.sol — createToken() (trimmed)
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:

DistributorV1.sol — DistributorConfig
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:

DistributionV1Factory.sol — createDistributor()
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:

  1. Deploys the new token with its allocations.
  2. Creates the Uniswap V3 pool at the chosen price and adds liquidity — LP tokens are sent to the dead address, locking liquidity forever.
  3. Injects the buy-back-and-burn share if requested.
  4. Deploys the distributor and funds it with the full distribution amount of the new token.
FactoryV1.sol — createTokenAndLiquidityAndDistribution() (trimmed)
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);
Supporting pieces: 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.