Post-Presale Operations
Step-by-step guide for every on-chain action after the presale ends — who does it, when, and why.
The Big Picture
When the presale ends, the protocol doesn't automatically unlock. A small sequence of actions must happen in order before buyers can claim their AIC. Think of it like a relay race — each leg hands off to the next.
PRESALE ENDS
│
▼
① Anyone calls finalizePresale()
→ Sets the clock for everything else
│
├──────────────────────────────────────────┐
▼ ▼
② Liquidity Operator seeds the DEX pool Marketing Operator can now
(must happen within 7 days) queue withdrawals
│
▼
③ Anyone calls enableClaims()
→ The token claim window is now open
│
▼
④ Token buyers claim their AIC
(30% at TGE, 65% at TGE+90d, 100% at TGE+180d)
— Running in parallel from Presale Start —
⑤ Dev Runway streams over 180 days
⑥ Team stream runs over 365 days
The critical path for buyers is steps ①②③. Steps ⑤ and ⑥ run independently from the claim pipeline.
Who's Who
Presale Participants (Buyers)
Contributors who sent USDC during the presale in exchange for an AIC allocation. Their tokens vest over time starting at TGE. Buyers interact directly with the ClaimModule contract to pull their tokens — no other action is needed from them before claiming.
What they care about: When can I get my tokens? How much can I claim right now?
The Liquidity Operator
The most time-sensitive role after finalization. Holds LIQUIDITY_OPERATOR_ROLE on LiquidityVault. Responsible for taking the 70% USDC held in the vault and providing it as liquidity on a DEX. Has a 7-day window after finalization. If the window is missed, anyone can trigger the fallback path.
What they care about: Getting liquidity seeded before the window expires — which unblocks token claims for all buyers.
The Dev Operator
Holds DEV_OPERATOR_ROLE on DevRunwayVault. Manages the day-to-day engineering budget. The vault streams USDC continuously over 180 days starting from presale start (not from finalization). The operator calls withdraw() whenever runway funds are needed.
The Team Operator
Holds TEAM_OPERATOR_ROLE on TeamStreamVault. Similar to the Dev Operator but for team compensation — linear stream over a full 365-day period.
The Marketing Operator
Holds MARKETING_OPERATOR_ROLE on MarketingVault. Marketing funds are available in full after finalization, but require a 2-day timelock: queue a withdrawal → wait 2 days → execute.
Step 1 — Finalize the Presale
Who: Anyone — no special wallet required. When: After the presale ends (time-based or hard cap reached). One-time: Cannot be called twice.
WebAI3Presale.finalizePresale()Call WebAI3Presale.isFinalizable() first — if true, the call will succeed.
What happens under the hood:
WebAI3Presale.finalizePresale()
├─ Confirms end condition is met (hard cap OR end timestamp)
├─ Sets presaleFinalized = true
├─ Clears any active emergency pause
├─ Records finalizedAt = current timestamp
├─ Notifies LiquidityVault → starts the 7-day operator window
└─ Notifies MarketingVault → unlocks queueWithdrawal()
Step 2 — Provide Liquidity
This is the gating step for everything buyers care about. Claims cannot open until liquidity is provisioned.
Path A — Normal Path (Liquidity Operator, within 7 days)
LiquidityVault.provideLiquidity()Transfers the entire USDC balance of the vault to the liquidityRecipient address in one transaction.
Requirements:
- Caller has
LIQUIDITY_OPERATOR_ROLE presaleFinalized == trueliquidityProvisioned == falseblock.timestamp <= finalizedAt + 7 days
Path B — Fallback Path (Anyone, after 7 days)
LiquidityVault.provideLiquidityFallback()Available after the 7-day operator window expires. No role restriction. Executes identically to Path A. This ensures the protocol can never be permanently stuck because one wallet went offline.
Step 3 — Enable Claims
Who: Anyone — no special wallet required. When: After both Step 1 and Step 2 are complete.
ClaimModule.enableClaims()The contract checks both preconditions before proceeding. Once this lands, buyers can start claiming.
Step 4 — Token Claims (Buyers)
Who: Each buyer, from the wallet they bought with. When: After Step 3, any time — but claimable amounts depend on how much time has passed since TGE.
Vesting Schedule
| When | Unlocks | Example: 10,000 AIC allocation |
|---|---|---|
| TGE | 30% | 3,000 AIC |
| TGE + 90 days | 35% more (65% total) | 3,500 more AIC |
| TGE + 180 days | 35% more (100% total) | 3,500 more AIC |
ClaimModule.claim()Buyers can claim as many times as they like. Each call transfers only newly vested tokens since the last claim. No need to claim at exactly the right moment — the contract tracks cumulative claimed amounts.
Check available balance before claiming:
ClaimModule.claimableAmount(address buyer) → uint256Step 5 — Vault Withdrawals (Operators)
These three vaults operate independently from the claim pipeline.
Dev Runway Vault
Budget: Up to 1,050,000 USDC (15% of the $7M hard cap) Stream: Linear over 180 days from presale start
Available = min(1,050,000 USDC × days_elapsed / 180, total_deposited) − already_withdrawn
DevRunwayVault.withdraw(amount)The dev stream started when the presale opened. By the time claims are enabled, a portion has already accumulated and is ready to withdraw.
Team Stream Vault
Budget: 10% of actual raised USDC Stream: Linear over 365 days from presale start
TeamStreamVault.withdraw(amount)Marketing Vault
Available from: After finalizePresale() is called
Mechanism: Full balance available, but requires a 2-day timelock
// Step 1 — Queue the withdrawal
MarketingVault.queueWithdrawal(amount)
// Step 2 — Wait 2 days
// Step 3 — Execute
MarketingVault.executeWithdrawal()
// Optional — Cancel before execution
MarketingVault.cancelQueuedWithdrawal()Full Timeline (Sepolia Dates)
PRESALE_START (~Mar 16, 2026)
│ Dev runway and team stream begin accumulating
│
PRESALE_END (~Jul 14, 2026) — or HARD_CAP hit
│
├─ Day 0 finalizePresale() called (anyone)
│ LiquidityVault operator window opens
│ MarketingVault queue unlocked
│
├─ Day 0–7 provideLiquidity() — preferred path
│
├─ Day 7+ If operator missed window:
│ provideLiquidityFallback() (anyone)
│
│ Once liquidity provisioned:
├─ ───── enableClaims() (anyone)
│
TGE (~Jul 15, 2026)
├─ Buyers can claim 30%
│
TGE + 90 days (~Oct 13, 2026)
├─ Buyers can claim 65% cumulative
│
TGE + 180 days (~Jan 11, 2027)
└─ Buyers can claim 100%
Stakeholder Checklists
Liquidity Operator — Time-Critical
- Monitor for
PresaleFinalizedevent onWebAI3Presale - Call
LiquidityVault.provideLiquidity()within 7 days of finalization - Confirm
liquidityProvisioned = trueon-chain
Anyone (help unblock the chain)
- Call
WebAI3Presale.finalizePresale()once end condition is met - Call
ClaimModule.enableClaims()after Steps 1 and 2 - Call
LiquidityVault.provideLiquidityFallback()if operator missed the 7-day window
Dev Operator — Ongoing
- Call
DevRunwayVault.withdraw(amount)when runway funds are needed - Check
withdrawableDev()to see currently available amount
Marketing Operator — Post-Finalization
- Call
MarketingVault.queueWithdrawal(amount)after finalization - Wait 2 days
- Call
MarketingVault.executeWithdrawal()to release funds
Token Buyers — After Claims Enabled
- Wait for
ClaimsEnabledevent onClaimModule - Call
ClaimModule.claim()at TGE, TGE+90d, TGE+180d (or any time after) - Check
claimableAmount(address)to see what's currently available
Error Reference
| Error | Contract | Meaning |
|---|---|---|
PresaleAlreadyFinalized |
Presale | finalizePresale() called twice |
PresaleNotFinalizable |
Presale | End condition not yet met |
LiquidityAlreadyProvisioned |
LiquidityVault | Provision called twice |
LiquidityWindowExpired |
LiquidityVault | Primary path after 7-day window |
LiquidityFallbackNotAvailable |
LiquidityVault | Fallback within operator window |
LiquidityNotProvisioned |
ClaimModule | enableClaims() called before liquidity |
AlreadyConfigured |
ClaimModule | enableClaims() called twice |
ClaimsNotEnabled |
ClaimModule | claim() before enableClaims() |
NothingClaimable |
ClaimModule | No vested and unclaimed balance |
MarketingLocked |
MarketingVault | queueWithdrawal() before finalization |
TimelockNotReady |
MarketingVault | executeWithdrawal() before 2-day wait |
WithdrawalExceedsLimit |
Dev/Team/MarketingVault | Requested amount exceeds available |