Skip to main content

🔍 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

// 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

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

ComponentStatusIssue
VaultActivationBatcher✅ CorrectNone
Token Flow✅ CorrectNone
Approval Flow✅ CorrectNone
CCALaunchStrategy⚠️ Needs FixonlyOwner blocks batcher

🎯 Action Required

To deploy CCA with AA batcher:

  1. Update CCALaunchStrategy to use approved launchers
  2. Deploy both contracts
  3. Approve VaultActivationBatcher in CCALaunchStrategy
  4. 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. 🔧