> ## Documentation Index
> Fetch the complete documentation index at: https://docs.veto.fun/llms.txt
> Use this file to discover all available pages before exploring further.

# Contract Reference

> The veto.fun smart contracts (VetoDotFun, HoodToken, and FeeLocker): functions, events, and errors.

Three contracts (Solidity 0.8.30, OpenZeppelin-based) run the entire protocol. Integrators only need the **VetoDotFun** address. Everything else is discoverable from it.

## VetoDotFun

The singleton that combines the token factory, every bonding curve, the fee ledger, and the Uniswap v3 migrator.

### Launching

```solidity theme={null}
function createToken(
    string calldata name,
    string calldata symbol,
    string calldata metadataURI,
    uint256 minTokensOut
) external payable returns (address token);
```

Deploys a `HoodToken` and opens its curve. `msg.value` must cover the flat creation fee (read it from `feeConfig()`; currently 0.001 ETH); any ETH beyond it executes an optional dev buy at the public starting price, with `minTokensOut` protecting against front-running. The current global fee config is snapshotted into the token's `CurveState`; its fees never change afterwards. Emits `TokenCreated` (which carries the snapshot).

### Trading

```solidity theme={null}
function buy(address token, uint256 minTokensOut, uint256 deadline)
    external payable returns (uint256 tokensOut);

function buyExactTokens(address token, uint256 tokensOut, uint256 deadline)
    external payable;  // refunds excess ETH

function sell(address token, uint256 tokenAmount, uint256 minEthOut, uint256 deadline)
    external returns (uint256 ethOut);  // requires prior approve

function sellWithPermit(
    address token, uint256 tokenAmount, uint256 minEthOut, uint256 deadline,
    uint8 v, bytes32 r, bytes32 s
) external returns (uint256 ethOut);   // single-tx sell via EIP-2612
```

A buy that exceeds the remaining curve supply fills to exactly the end, refunds the excess ETH, and sets `graduated = true`. Emits `Trade` on every fill and `Graduated` on the final one.

### Views & quotes

```solidity theme={null}
function quoteBuy(address token, uint256 grossEthIn)
    external view returns (uint256 tokensOut, uint256 fee, uint256 ethUsed);
function quoteBuyExact(address token, uint256 tokensOut)
    external view returns (uint256 ethNeeded, uint256 fee);
function quoteSell(address token, uint256 tokenAmount)
    external view returns (uint256 ethOut, uint256 fee);

function currentPrice(address token) external view returns (uint256);      // wei per 1e18 tokens
function curveProgressBps(address token) external view returns (uint256);  // 0–10000
function getTokens(uint256 offset, uint256 limit) external view returns (address[] memory);
function getCurveStates(address[] calldata tokens) external view returns (CurveState[] memory);
function curves(address token) external view returns (CurveState memory);
```

`CurveState` fields: `virtualEth`, `virtualToken`, `realTokensLeft`, `realEth`, `creator`, `graduated`, `migrated`, plus the launch-time fee snapshot `protocolFeeBps`, `creatorFeeBps`, `creatorLpShareBps` (uint16s, fixed for the token's lifetime).

### Migration

```solidity theme={null}
function migrate(address token) external returns (address pool, uint256 tokenId);
```

Permissionless and parameter-free. Wraps the raised ETH, mints a full-range Uniswap v3 position (1% fee tier) at the final curve price, and locks the position NFT in the FeeLocker. Includes a bounded corrective swap to neutralize hostile pool pre-initialization. Leftover tokens burn to `0xdEaD`; leftover WETH accrues to protocol fees. Emits `Migrated`.

### Fees

```solidity theme={null}
function claimCreatorFees(address token) external;              // fee recipient or claimAuthority
function claimCreatorFeesBatch(address[] calldata tokens) external; // same gate; airdrops each token's fees to its own recipient
function claimProtocolFees() external;                          // treasury only
function setFeeRecipient(address token, address newRecipient) external; // current recipient only

function creatorFeesOwed(address token) external view returns (uint256);
function protocolFeesOwed() external view returns (uint256);
function feeRecipientOf(address token) external view returns (address);
function feeConfig() external view returns (uint16 protocolFeeBps, uint16 creatorFeeBps, uint16 creatorLpShareBps, uint96 creationFee); // GLOBAL config for future launches
function creatorLpShareBpsOf(address token) external view returns (uint256); // the token's snapshot
function claimAuthority() external view returns (address);
```

**Fee model:** the global `feeConfig` is owner-tunable within hard caps (`MAX_TOTAL_FEE_BPS = 500`, `MAX_CREATION_FEE = 0.1 ether`), and `createToken` snapshots it into the token's `CurveState`. A token's fees are read from its snapshot on every trade and harvest; config changes apply to future launches only.

**Claim gating:** payouts always go to the recorded recipient, but only the recipient itself or the `claimAuthority` (the platform's backend claimer, rotatable by the owner) may trigger creator claims; only the treasury may trigger protocol claims.

### Owner surface (complete list)

```solidity theme={null}
function setFeeConfig(FeeConfig calldata c) external;   // future launches only; hard-capped
function setClaimAuthority(address a) external;         // rotate/disable the backend claimer
function setTreasury(address newTreasury) external;
function setLocker(address locker) external;            // one-time, already consumed at deployment
```

There is deliberately no withdraw, pause, upgrade, seize, or retroactive fee-change function.

### Events

```solidity theme={null}
event TokenCreated(address indexed token, address indexed creator, string name, string symbol, string metadataURI,
                   uint16 protocolFeeBps, uint16 creatorFeeBps, uint16 creatorLpShareBps); // fee snapshot included
event Trade(address indexed token, address indexed trader, bool isBuy, uint256 ethGross, uint256 tokenAmount, uint256 fee, uint256 virtualEth, uint256 virtualToken);
event Graduated(address indexed token, uint256 ethRaised);
event Migrated(address indexed token, address pool, uint256 tokenId, uint256 ethAmount, uint256 tokenAmount);
event FeeConfigSet(uint16 protocolFeeBps, uint16 creatorFeeBps, uint16 creatorLpShareBps, uint96 creationFee);
event ClaimAuthoritySet(address indexed authority);
```

### Custom errors

`CurveClosed`, `CurveStillOpen`, `AlreadyMigrated`, `Expired`, `SlippageExceeded`, `UnknownToken`, `ZeroAmount`, `ZeroAddress`, `FeeTooHigh`, `NotFeeRecipient`, `NotTreasury`, `InsufficientCreationFee`, `LockerNotSet`, `LockerAlreadySet`, `EthTransferFailed`, `OnlyWeth`, `NotPool`

## HoodToken

The per-launch ERC-20, deployed by `createToken`:

* OpenZeppelin `ERC20` + `ERC20Permit` (EIP-2612), 18 decimals
* Fixed supply of 1,000,000,000 × 1e18, minted once to the launchpad
* `metadataURI()`: immutable token metadata pointer (e.g. `ipfs://…`)
* **No** owner, mint, burn-by-admin, pause, blacklist, or fee-on-transfer

## FeeLocker

The immutable, ownerless vault for graduated liquidity:

```solidity theme={null}
function positionOf(address token) external view returns (uint256 tokenId); // 0 = not migrated
function collectFees(address token) external;  // fee recipient, treasury, or claimAuthority only
```

The locker has no function that can transfer a position out; locked liquidity is permanent by construction. Each harvest is split creator/treasury at the token's launch-time snapshot, read live from the launchpad's `creatorLpShareBpsOf(token)` (30/70 under the current config). One call always pays both parties; Uniswap collects the whole position at once.

## Curve constants

```solidity theme={null}
uint256 constant TOTAL_SUPPLY    = 1_000_000_000e18;
uint256 constant VIRTUAL_TOKEN_0 = 1_073_000_000e18;
uint256 constant SALE_SUPPLY     =   793_100_000e18;
uint256 constant POOL_SUPPLY     = TOTAL_SUPPLY - SALE_SUPPLY; // 206_900_000e18
// virtualEth0: immutable constructor parameter (1.6 ETH at launch)
uint24  constant POOL_FEE   = 10000;    // Uniswap v3 1% tier
int24   TICK_LOWER/UPPER    = ±887200;  // full range
uint256 constant MAX_TOTAL_FEE_BPS = 500;      // hard cap on the tunable trade fee
uint256 constant MAX_CREATION_FEE  = 0.1 ether; // hard cap on the tunable creation fee
```

All rounding favors the pool (`Math.ceilDiv` on reserve division) so the invariant `k` never decreases.

## Deployed addresses

Live on Robinhood Chain mainnet (4663) since block 9,824,773, source-verified on Blockscout:

| Contract   | Address                                                                                                                                  |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| VetoDotFun | [`0x152172137fa870a51DFde25a0dFc0bE9ad4dEE5A`](https://robinhoodchain.blockscout.com/address/0x152172137fa870a51DFde25a0dFc0bE9ad4dEE5A) |
| FeeLocker  | [`0x98f721ca716214c425DCF9D7c098A054869aa85E`](https://robinhoodchain.blockscout.com/address/0x98f721ca716214c425DCF9D7c098A054869aa85E) |

See [Developer Overview](/developers/overview) for the canonical Uniswap and WETH addresses the protocol builds on.
