Skip to main content

🔐 MULTISIG OWNER SETUP

UPDATED FOR MULTISIG OWNERSHIP

The StrategyDeploymentBatcher now accepts a custom owner parameter, allowing you to use your multisig wallet as the owner of all deployed strategies!


🎯 YOUR MULTISIG:

0x7d429eCbdcE5ff516D6e0a93299cbBa97203f2d3

📋 WHAT CHANGED:

Before:

function batchDeployStrategies(
address underlyingToken,
address quoteToken,
address creatorVault,
address _ajnaFactory,
uint24 v3FeeTier,
uint160 initialSqrtPriceX96
) external

Owner was: msg.sender (the caller)

After:

function batchDeployStrategies(
address underlyingToken,
address quoteToken,
address creatorVault,
address _ajnaFactory,
uint24 v3FeeTier,
uint160 initialSqrtPriceX96,
address owner // ⭐ NEW PARAMETER
) external

Owner is: The specified owner address (your multisig)


🚀 HOW TO DEPLOY:

Transaction 1: Deploy All Strategies

DeploymentResult memory result = batcher.batchDeployStrategies(
creatorToken, // CREATOR token
0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, // USDC on Base
creatorVault, // Your CreatorOVault
ajnaFactory, // Ajna factory (or address(0))
3000, // 0.3% fee tier
sqrtPriceX96, // Initial price
0x7d429eCbdcE5ff516D6e0a93299cbBa97203f2d3 // ⭐ YOUR MULTISIG
);

Result:

  • ✅ CharmAlphaVault deployed (pendingGovernance = your multisig)
  • ✅ No separate CharmAlphaStrategy deployed (rebalance is embedded in CharmAlphaVaultDeploy)
  • ✅ CreatorCharmStrategyV2 deployed (owner = your multisig)
  • ✅ AjnaStrategy deployed (owner = your multisig)

Transaction 2: Accept Governance (FROM MULTISIG)

Important: This transaction MUST be sent from your multisig wallet!

CharmAlphaVault(result.charmVault).acceptGovernance();

After this:

  • ✅ Your multisig is now the full owner of CharmAlphaVault
  • ✅ You can adjust fees, caps, strategy, etc.

🔐 OWNERSHIP SUMMARY:

ContractOwnerType
CharmAlphaVaultYour MultisigGovernance (after accepting)
CharmAlphaStrategy❌ Not deployedEmbedded
CreatorCharmStrategyV2Your MultisigOwner
AjnaStrategyYour MultisigOwner

🛡️ WHY MULTISIG IS BETTER:

AspectEOAMultisig
Security❌ Single point of failure✅ Multiple signers required
Key Loss❌ If lost, funds gone forever✅ Other signers can recover
Compromise❌ One key = full access✅ Attacker needs multiple keys
Transparency❌ No visibility✅ All signers see transactions
Accountability❌ No audit trail✅ Who signed what is recorded

Your multisig (0x7d429eCbdcE5ff516D6e0a93299cbBa97203f2d3) is the RIGHT choice! 🎉


📊 COMPLETE DEPLOYMENT FLOW:

┌─────────────────────────────────────────────────────┐
│ Step 1: ANYONE calls batchDeployStrategies() │
│ (Can be EOA, can be multisig, can be different) │
└─────────────────────────────────────────────────────┘

┌────────────────────────────┐
│ Contracts Deployed: │
│ - CharmAlphaVault │
│ - (no separate CharmAlphaStrategy) │
│ - CreatorCharmStrategyV2 │
│ - AjnaStrategy │
└────────────────────────────┘

┌────────────────────────────┐
│ Ownership Status: │
│ pendingGovernance = 0x7d..│
│ keeper = 0x7d... │
│ owner = 0x7d... │
└────────────────────────────┘

┌─────────────────────────────────────────────────────┐
│ Step 2: MULTISIG calls acceptGovernance() │
│ Must be called by: 0x7d429eCbdcE5ff516D6e0a93299cbBa97203f2d3 │
└─────────────────────────────────────────────────────┘

┌────────────────────────────┐
│ ✅ MULTISIG NOW OWNS ALL │
└────────────────────────────┘

⚠️ IMPORTANT NOTES:

1. Accept Governance MUST Come From Multisig

// ❌ WRONG - Called from different address
EOA.call(charmVault.acceptGovernance()) // Will REVERT

// ✅ CORRECT - Called from multisig
Multisig(0x7d429eCbdcE5ff516D6e0a93299cbBa97203f2d3).call(
charmVault.acceptGovernance()
)

2. You Don't Need to Deploy From Multisig

  • Anyone can call batchDeployStrategies() (costs gas)
  • The owner parameter determines ownership
  • Multisig only needs to accept governance (cheap transaction)

3. Ownership is Immediate for Most Contracts

  • CreatorCharmStrategyV2: Owned immediately ✅
  • AjnaStrategy: Owned immediately ✅
  • CharmAlphaStrategy: Not deployed (embedded) ✅
  • CharmAlphaVault: Requires acceptance ⚠️

🎯 CHECKLIST:

  • 1. Call batchDeployStrategies() with multisig address as owner parameter
  • 2. Note the returned result.charmVault address
  • 3. From your multisig, call CharmAlphaVault(address).acceptGovernance()
  • 4. Verify ownership by calling CharmAlphaVault.governance() → should return your multisig
  • 5. Test a governance function (like setProtocolFee()) from multisig ✅
  • 6. Add strategies to your CreatorOVault
  • 7. Start accepting deposits!

💡 EXAMPLE DEPLOYMENT SCRIPT:

// Step 1: Deploy (can be from any address)
const batcher = new ethers.Contract(batcherAddress, batcherABI, signer);
const tx = await batcher.batchDeployStrategies(
creatorToken,
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC
vaultAddress,
ajnaFactory,
3000,
sqrtPriceX96,
"0x7d429eCbdcE5ff516D6e0a93299cbBa97203f2d3" // Your multisig
);
const receipt = await tx.wait();

// Parse event to get addresses
const event = receipt.events.find(e => e.event === "StrategiesDeployed");
const charmVaultAddress = event.args.result.charmVault;

// Step 2: Accept from multisig (using Safe SDK or direct call)
const charmVault = new ethers.Contract(
charmVaultAddress,
charmVaultABI,
multisigSigner // ⚠️ Must be multisig signer
);
await charmVault.acceptGovernance();

console.log("✅ Multisig now owns CharmAlphaVault!");

🔐 SECURITY BEST PRACTICES:

  1. Use multisig for ownership (you're doing this!)
  2. Require multiple signers (2-of-3 or 3-of-5 recommended)
  3. Keep signer keys separate (different hardware wallets)
  4. Test on testnet first (Base Sepolia)
  5. Verify all contract addresses before accepting governance
  6. Document all transactions for audit trail

🎉 YOU'RE ALL SET!

Your multisig 0x7d429eCbdcE5ff516D6e0a93299cbBa97203f2d3 will own all deployed strategies!

This is much more secure than using an EOA. Great decision! 🛡️