Smart contracts for sqrtDAO: a permissionless launch pad where a project can create a token, seed a Uniswap V3 pool and run an epoch-based distribution that rewards participation pro-rata through configurable emission curves. Open to anyone, no allowlist required (optional allowlist supported per distribution).
Currently deployed on Base, Sepolia and Robinhood Chain (see Deployments).
A launch usually has three parts that can be combined or used separately:
- Token —
TokenV1is an ERC20 with vesting allocations (Allocationper recipient) and on-chain, owner-editable-then-lockable metadata (MetadataStore, ERC-7729 / ERC-7572 / EIP-1046 getters). - Liquidity —
FactoryV1creates/initializes a Uniswap V3 pool at an exactsqrtPriceX96(reverting if the pool already exists at another price), mints a full-range position and burns the LP NFT to0xdEaD. - Distribution —
DistributorV1runsNUMBER_OF_EPOCHSepochs. Users pay aPARTICIPATION_TOKENper epoch; after each epoch ends, its reward (computed by the chosenEmissionFunction) is released and split among participants pro-rata to what they put in. Epoch funds are split through shares (Share[], basis points that must sum to 100%) whose "hooks" are arbitrary calls — the protocol fee, buy & burn and any creator routing all happen there.
| Contract | Role |
|---|---|
src/products/token-distribution/v1/FactoryV1.sol |
Main entry point. Holds owner config (protocolFeeBps, releaseOperator, buyBackAndBurnMinBps), injects the protocol fee and buy & burn shares into every launch, and exposes createToken, createDistributor, createPoolAndAddLiquidity, createTokenAndLiquidityAndDistribution, createLiquidityAndDistribution. |
src/products/token-distribution/v1/TokenV1.sol |
ERC20 launch token. Mints vesting allocations at deploy, claim() mints whatever has vested so far. |
src/products/token-distribution/v1/DistributorV1.sol |
Epoch distribution: participate / participateMany, claim / claimMany (with optional third-party claim fee), releaseEpochFunds, release policies (Factory, Creator, CreatorOrFactory, Anyone), optional ECDSA allowlist, view helpers for frontends. |
src/products/token-distribution/v1/EthParticipationRouter.sol |
Converts native ETH into the chain's WETH and calls DistributorV1.participate, so users can join with ETH. Stateless and ownerless. |
src/products/token-distribution/v1/TokenV1Factory.sol |
Deploys TokenV1 instances (keeps FactoryV1 below the EIP-170 size limit) and tracks creatorOf / token list. |
src/products/token-distribution/v1/DistributionV1Factory.sol |
Deploys DistributorV1 instances. |
src/common/FeeVault.sol |
Custodies the protocol fee. Only its own owner can cashOut, so changing the factory owner never redirects already-collected fees. |
src/products/token-distribution/utils/hooks/TransferToHook.sol |
Share hook: transfers the caller's allowance of a token to a fixed recipient (used for the protocol fee). |
src/products/token-distribution/utils/hooks/BuyAndBurnHookV3.sol |
Share hook: swaps the participation token to the distribution token through Uniswap V3 and sends the output to 0xdEaD. |
src/products/token-distribution/utils/emission-function/* |
IEmissionFunction implementations: FixedEmission, LinearEmission (exact O(1) totals), ExponentialEmission (growth or decay). |
src/common/Shares.sol |
Share struct + validation/splitting helpers (basis points, 100% total). |
src/common/Metadata.sol |
Reusable owner-gated key/value metadata store with a one-time irreversible lock. |
src/common/Hook.sol |
Hook struct (contractAddress, callData) and revert-on-error / emit-on-error call helpers. |
script/products/token-distribution/v1/FactoryV1.s.sol |
Deployment script for a real chain (Uniswap addresses + WETH come from env vars). |
script/products/token-distribution/v1/FactoryV1Local.s.sol |
Deployment script with mock Uniswap/Permit2 contracts for local testing. |
test/ |
Unit and integration tests (factory, distributor, liquidity, emissions, metadata, shares, router, hooks). |
dune/ contains the Dune queries used for analytics, and abis/ is where exported ABIs are placed.
The same deployer and nonce sequence was used on all three chains, so every contract has the same address on Base, Sepolia and Robinhood Chain. Only the chain-specific external tokens/protocols differ.
Because these addresses come from the deployer EOA's nonce (CREATE, not CREATE2), adding a
new chain requires running script/products/token-distribution/v1/FactoryV1.s.sol from the same EOA while its nonce on that
chain is 0, without skipping or reordering any deployment (including the sample token and
distributor).
| Contract | Base | Sepolia | Robinhood Chain |
|---|---|---|---|
| FactoryV1 (entry point) | 0x0d7c71B0E33636555C237899DfF80F847637186e |
same | same |
| TokenV1Factory | 0x79323C318392Bffd0Db521866DdC5c8bBfc2a659 |
same | same |
| DistributionV1Factory | 0x948F9cfdf9d7Dd53df16aC060012b14A7D0CBeE6 |
same | same |
| FeeVault | 0xE89B5AF07821A69c9755DFDE7DB0eD2E49Ae7FCc |
same | same |
| FixedEmission | 0xa616f9d40DfBe52836B47744BcF2F4be0cDE4ACb |
same | same |
| LinearEmission | 0xDA9A1c5F6424EE64e814bF40Eb95c952Ee296AD8 |
same | same |
| ExponentialEmission | 0x77EaAff0F59440E8B2227843FBCd2F7513C7ef61 |
same | same |
| TransferToHook | 0xaC7073380A91415D9bfEB57b6492CC628d146B42 |
same | same |
| BuyAndBurnHookV3 | 0xD778ea77847aBf6234E0383226fb5f7b7a08aB45 |
same | same |
| EthParticipationRouter | 0xD9412770F615B059A35cd2bA8207Cf0157225304 |
same | same |
Sample TokenV1 (Sample Token / SAMPLE) |
0xf1016aE1f485C6F18E7AC17304A06331ea5d3052 |
same | same |
| Sample DistributorV1 | 0xB9d646ef75643037013ef3E742a8B77Fb482C5Ff |
same | same |
Owner (initialOwner) |
0xc5C600799A5e0937F549BE6931b46013551177c3 |
same | same |
The sample token/distributor are throwaway instances deployed only so the TokenV1 /
DistributorV1 bytecode is verified on the explorer — every instance created later by the
factories shares the same bytecode and therefore resolves to that verified source.
Chain-specific dependencies (these are not the same address):
| Dependency | Base | Sepolia | Robinhood Chain |
|---|---|---|---|
| WETH | 0x4200000000000000000000000000000000000006 |
0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14 |
0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73 |
| Uniswap V3 Position Manager | 0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1 |
0x1238536071E1c677A632429e3655c799b22cDA52 |
0x73991a25c818bf1f1128deaab1492d45638de0d3 |
| Uniswap V3 Swap Router | 0x2626664c2603336E57B271c5C0b26F421741e481 |
0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E |
0xcaf681a66d020601342297493863e78c959e5cb2 |
| Permit2 | 0x000000000022D473030F116dDEE9F6B43aC78BA3 |
same (canonical) | same (canonical) |
WETH for the
EthParticipationRoutermust be the wrapped-native token of the target chain.0x4200000000000000000000000000000000000006is the OP-Stack predeploy and only valid on Base. Robinhood Chain is an Arbitrum Orbit L2 (chainId 4663, ETH gas) with a Blockscout explorer (https://robinhoodchain.blockscout.com), so its WETH is the bridged L2 WETH above. Verify Robinhood deployments with--verify --verifier sourcify. Its Blockscout API is behind Cloudflare (which blocks CLI verification requests), but Blockscout imports Sourcify verifications automatically. An Etherscan API key is not used.