Skip to Content
Smart ContractsScoutFundV2

ScoutFundV2

ScoutFundV2 is a protocol-owned liquidity fund that automatically invests in company tokens when they graduate from the bonding curve to Uniswap V4. It receives 25% of protocol fees via FeeSplitterV2 and deploys a fixed USDC seed amount into each newly public company.

Deployed at: 0xd840C9BD1cCA5B5F70883f173EDcc626cf1d41a2 (Base Sepolia)

Key Properties

PropertyValue
Investment TokenUSDC (6 decimals)
Default Seed Amount100 USDC per company
Max Seed Amount10,000 USDC
Max Positions100 unique tokens
Swap RouterV4SwapHelper (0xf6E8cD6f7c4fd83b0F8a053c3B29d95383fEb4D0)
Default Pool Fee3000 (0.30%)

How It Works

  1. A company token graduates from its bonding curve (market cap hits $10K).
  2. CompanyTokenLauncher calls investInCompany(companyToken, 0) on ScoutFundV2.
  3. ScoutFundV2 swaps seedAmount USDC for company tokens via V4SwapHelper.
  4. Acquired tokens are held as protocol-owned liquidity (POL) permanently.
  5. Positions are tracked per-token with investment counts and totals.

The fund operates as a passive investor. It does not divest — all positions are held permanently. Profit can be withdrawn by an admin via withdrawProfit().

Structs

struct Position { address token; // Company token address uint256 totalInvested; // Cumulative USDC spent uint256 totalTokensAcquired; // Cumulative tokens received uint256 investmentCount; // Number of investment transactions uint256 investedAt; // Timestamp of most recent investment }

Interface

Investment

/// @notice Invest seedAmount of USDC into a company token via Uniswap V4. /// Only callable by addresses with INVESTOR_ROLE. /// @param companyToken The company token to purchase /// @param minAmountOut Minimum tokens to receive (slippage protection). /// Use 0 only during same-tx pool initialization. /// @return tokensOut The amount of company tokens acquired function investInCompany( address companyToken, uint256 minAmountOut ) external returns (uint256 tokensOut);

Admin Functions

/// @notice Update the USDC seed amount invested per company. /// @param newSeedAmount Must be > 0 and <= MAX_SEED_AMOUNT (10,000 USDC) function setSeedAmount(uint256 newSeedAmount) external; /// @notice Update the default Uniswap V4 pool fee tier. /// @param newFee Pool fee (e.g., 3000 = 0.30%) function setDefaultPoolFee(uint24 newFee) external; /// @notice Withdraw acquired tokens from the fund. /// @param token The token to withdraw /// @param amount The amount to withdraw function withdrawProfit(address token, uint256 amount) external; /// @notice Pause the contract (blocks all investments). function pause() external; /// @notice Unpause the contract. function unpause() external;

Views

/// @notice Get the full position for a specific company token. function getPosition(address companyToken) external view returns (Position memory); /// @notice Total number of unique positions held. function getPositionCount() external view returns (uint256); /// @notice The USDC amount invested per company. function seedAmount() external view returns (uint256); /// @notice The default Uniswap V4 pool fee tier. function defaultPoolFee() external view returns (uint24);

Events

event CompanyInvested(address indexed companyToken, uint256 usdcIn, uint256 tokensOut); event SeedAmountUpdated(uint256 oldAmount, uint256 newAmount); event DefaultPoolFeeUpdated(uint24 oldFee, uint24 newFee); event ProfitWithdrawn(address indexed token, uint256 amount, address indexed to);

Errors

error ZeroAddress(); // Invalid token address error ZeroAmount(); // Seed amount is zero error InsufficientBalance(); // Not enough USDC for investment error SeedAmountTooHigh(); // Exceeds MAX_SEED_AMOUNT or MAX_POSITIONS

Roles

RolePermission
INVESTOR_ROLECall investInCompany()
DEFAULT_ADMIN_ROLEConfig setters, withdrawProfit(), pause()/unpause()

The INVESTOR_ROLE is typically granted to the CompanyTokenLauncher contract so it can trigger investment automatically during the graduation flow. It can also be granted to a backend worker for manual investments.

Integration with CompanyTokenLauncher

The CompanyTokenLauncher holds a reference to ScoutFundV2 and calls it during graduation:

// In CompanyTokenLauncher._graduateToV4(): if (scoutFund != address(0)) { try IScoutFundV2(scoutFund).investInCompany(token, 0) {} catch (bytes memory reason) { emit ScoutInvestFailed(companyId, token, reason); } }

The try/catch wrapper ensures a ScoutFund failure does not block graduation. If the fund has insufficient USDC or is paused, the graduation proceeds and a ScoutInvestFailed event is emitted.

Funding

The fund receives USDC from FeeSplitterV2, which routes 25% of all protocol fees to the Scout Fund. Protocol fee sources include:

  • 100 USDC company registration fee
  • 2% treasury funding fee
  • 2% budget allocation fee
  • 2% service economy fee
  • 2.5% CeosHook swap fee on graduated token trades

USDC Allowance

At construction, ScoutFundV2 pre-approves the V4SwapHelper for type(uint256).max USDC. This removes the need for per-swap approval transactions, making each investment a single-call operation.

Security

  • ReentrancyGuard on investInCompany() and withdrawProfit()
  • Pausable allows emergency halt of all investments
  • AccessControl with separate INVESTOR_ROLE and DEFAULT_ADMIN_ROLE
  • SafeERC20 for all token transfers
  • MAX_SEED_AMOUNT cap (10,000 USDC) prevents accidental over-investment
  • MAX_POSITIONS limit (100) prevents unbounded gas costs in position tracking
  • Pre-approved USDC allowance eliminates approval front-running risk