🔍 CCA Deployment Deep Verification
✅ CCA Flow is CORRECT - But Has 1 CRITICAL Issue
I've traced through the entire CCA launch flow. Here's what happens:
📊 The Complete CCA Launch Flow
Step-by-Step Breakdown:
User → VaultActivationBatcher.batchActivate()
↓
1. Pull CREATOR tokens from user
↓
2. Deposit to CreatorOVault
→ Receive vault shares (sTokens)
↓
3. Wrap shares via CreatorOVaultWrapper
→ Receive wsTokens (ShareOFT)
↓
4. Approve CCA strategy to spend wsTokens
↓
5. Call CCALaunchStrategy.launchAuctionSimple()
↓
→ CCALaunchStrategy.launchAuction()
↓
a. Transfer wsTokens from batcher to CCALaunchStrategy
b. Approve CCA_FACTORY to spend wsTokens
c. Call CCA_FACTORY.initializeDistribution()
d. Returns auction address
↓
6. Return remaining wsTokens to user
⚠️ CRITICAL ISSUE FOUND
Problem: onlyOwner Modifier
// In CCALaunchStrategy.sol line 297-300
function launchAuctionSimple(
uint256 amount,
uint128 requiredRaise
) external onlyOwner nonReentrant returns (address auction) {
// ...
}
This means:
❌ Only the OWNER of CCALaunchStrategy can call launchAuctionSimple()
❌ VaultActivationBatcher cannot call it directly
❌ User cannot call it via batcher
🚨 What This Means for Deployment
Current Setup:
// VaultActivationBatcher (line 117)
auction = ICCAStrategy(ccaStrategy).launchAuctionSimple(auctionAmount, requiredRaise);
What Will Happen:
User calls VaultActivationBatcher.batchActivate()
↓
Batcher pulls tokens ✅
↓
Batcher deposits to vault ✅
↓
Batcher wraps to wsTokens ✅
↓
Batcher approves CCA strategy ✅
↓
Batcher calls launchAuctionSimple()
↓
❌ REVERT: "Ownable: caller is not the owner"
RESULT: Transaction fails ❌
🔧 3 Ways to Fix This
Option 1: Remove onlyOwner from launchAuctionSimple ⭐ RECOMMENDED
// In CCALaunchStrategy.sol
function launchAuctionSimple(
uint256 amount,
uint128 requiredRaise
) external nonReentrant returns (address auction) { // Remove onlyOwner
// Transfer tokens from msg.sender (the batcher)
auctionToken.safeTransferFrom(msg.sender, address(this), amount);
// Rest of function...
}
Pros:
- ✅ Anyone with wsTokens can launch auction
- ✅ Works with VaultActivationBatcher
- ✅ Simple fix
Cons:
- ⚠️ Anyone can launch auction (but only if they have tokens)
Option 2: Add Approved Launchers Mapping
// In CCALaunchStrategy.sol
mapping(address => bool) public approvedLaunchers;
modifier onlyApprovedOrOwner() {
require(msg.sender == owner() || approvedLaunchers[msg.sender], "Not approved");
_;
}
function setApprovedLauncher(address launcher, bool approved) external onlyOwner {
approvedLaunchers[launcher] = approved;
}
function launchAuctionSimple(
uint256 amount,
uint128 requiredRaise
) external onlyApprovedOrOwner nonReentrant returns (address auction) {
// ...
}
Pros:
- ✅ Controlled access
- ✅ Owner can approve VaultActivationBatcher
- ✅ Multiple batchers can be approved
Cons:
- ⚠️ Requires deployment update
- ⚠️ Extra step to approve batcher
Option 3: Two-Step Process (No Code Changes)
// Step 1: User deposits/wraps manually
vault.deposit(amount, user);
wrapper.wrap(shares);
// Step 2: User approves CCALaunchStrategy
wsToken.approve(ccaStrategy, auctionAmount);
// Step 3: Owner (creator) launches auction with user's tokens
ccaStrategy.launchAuctionSimple(auctionAmount, requiredRaise);
Pros:
- ✅ No code changes needed
- ✅ Works with current contract
Cons:
- ❌ Not a single transaction
- ❌ User must do multiple steps
- ❌ Not as smooth UX
🎯 Recommended Solution
Update CCALaunchStrategy to Use Approved Launchers
This gives you the best of both worlds:
- ✅ Security (only approved addresses can launch)
- ✅ Flexibility (approve VaultActivationBatcher)
- ✅ Single transaction UX
Implementation:
// Add to CCALaunchStrategy.sol
mapping(address => bool) public approvedLaunchers;
event LauncherApproved(address indexed launcher, bool approved);
modifier onlyApprovedOrOwner() {
require(msg.sender == owner() || approvedLaunchers[msg.sender], "Not approved");
_;
}
function setApprovedLauncher(address launcher, bool approved) external onlyOwner {
approvedLaunchers[launcher] = approved;
emit LauncherApproved(launcher, approved);
}
function launchAuctionSimple(
uint256 amount,
uint128 requiredRaise
) external onlyApprovedOrOwner nonReentrant returns (address auction) {
// Transfer tokens from caller
auctionToken.safeTransferFrom(msg.sender, address(this), amount);
// Create default linear auction steps
bytes memory auctionSteps = _createLinearSteps(defaultDuration);
// Use default floor price
uint256 floorPrice = defaultFloorPrice;
// Forward to main function
return this.launchAuction(amount, floorPrice, requiredRaise, auctionSteps);
}
Then after deployment:
ccaStrategy.setApprovedLauncher(address(vaultActivationBatcher), true);
✅ After Fix: Complete Flow Will Work
1. Deploy CCALaunchStrategy (with approved launchers)
2. Deploy VaultActivationBatcher
3. Call ccaStrategy.setApprovedLauncher(batcherAddress, true)
4. User calls batcher.batchActivate()
↓
5. Batcher pulls tokens ✅
6. Batcher deposits to vault ✅
7. Batcher wraps to wsTokens ✅
8. Batcher approves CCA strategy ✅
9. Batcher calls launchAuctionSimple() ✅
10. CCA checks: msg.sender (batcher) is approved ✅
11. CCA pulls wsTokens from batcher ✅
12. CCA creates auction ✅
13. Returns auction address ✅
14. Batcher returns remaining tokens to user ✅
SUCCESS! 🎉
📋 Verification Summary
| Component | Status | Issue |
|---|---|---|
| VaultActivationBatcher | ✅ Correct | None |
| Token Flow | ✅ Correct | None |
| Approval Flow | ✅ Correct | None |
| CCALaunchStrategy | ⚠️ Needs Fix | onlyOwner blocks batcher |
🎯 Action Required
To deploy CCA with AA batcher:
- ✅ Update CCALaunchStrategy to use approved launchers
- ✅ Deploy both contracts
- ✅ Approve VaultActivationBatcher in CCALaunchStrategy
- ✅ Test via AA
OR
Use Option 3 (two-step process) with current contracts, but worse UX.
💡 Bottom Line
The code logic is correct, BUT:
- ❌ Current CCALaunchStrategy won't work with VaultActivationBatcher
- ✅ Easy fix: Add approved launchers mapping
- ✅ After fix: Everything will deploy correctly via AA
Current status: CCA needs 1 contract update before AA deployment works. 🔧