Skip to main content
The TreasuryFactory contract is responsible for deploying treasury contracts for campaigns. It manages treasury implementations, handles platform-specific configurations, and creates treasury instances using the clone pattern for gas efficiency.

Overview

contract TreasuryFactory is ITreasuryFactory, AdminAccessChecker {
    mapping(bytes32 => mapping(uint256 => address)) private implementationMap;
    mapping(address => bool) private approvedImplementations;
}

Key Features

  • Treasury Deployment: Creates treasury contracts for campaigns using clone pattern
  • Implementation Management: Registers and approves treasury implementations per platform
  • Platform-Specific: Each platform can have multiple treasury implementations
  • Protocol Approval: All implementations must be approved by protocol admin before use
  • Access Control: Platform admins register implementations, protocol admin approves them
  • Gas Efficient: Uses minimal proxy pattern for low-cost deployments

State Variables

ImplementationMap

VariableTypeDescription
implementationMapmapping(bytes32 => mapping(uint256 => address))Maps platform and implementation ID to implementation address

ApprovedImplementations

VariableTypeDescription
approvedImplementationsmapping(address => bool)Whether an implementation is approved by protocol admin

Functions

Constructor

constructor(IGlobalParams globalParams);
Parameters:
  • globalParams: Global parameters contract reference
Effects:
  • Initializes admin access checker with GlobalParams
  • Sets up access control for platform and protocol admins

Treasury Implementation Registration

Register Treasury Implementation

function registerTreasuryImplementation(
    bytes32 platformHash,
    uint256 implementationId,
    address implementation
) external override onlyPlatformAdmin(platformHash);
Parameters:
  • platformHash: Platform identifier
  • implementationId: Unique ID for this implementation
  • implementation: Contract address of the treasury implementation
Effects:
  • Registers treasury implementation for platform
  • Can be called before approval
Requirements:
  • Only callable by platform admin
  • Implementation address must be non-zero
Usage:
  • Platform admin registers their treasury implementations
  • Multiple implementations can be registered per platform
  • Implementation IDs are platform-specific

Approve Treasury Implementation

function approveTreasuryImplementation(
    bytes32 platformHash,
    uint256 implementationId
) external override onlyProtocolAdmin;
Parameters:
  • platformHash: Platform identifier
  • implementationId: Implementation ID to approve
Effects:
  • Approves implementation for use in deployments
  • Emits approval event
Requirements:
  • Only callable by protocol admin
  • Implementation must be registered
Security:
  • Protocol admin review required before deployments
  • Prevents malicious implementations from being used

Disapprove Treasury Implementation

function disapproveTreasuryImplementation(address implementation) 
    external 
    override 
    onlyProtocolAdmin;
Parameters:
  • implementation: Implementation address to disapprove
Effects:
  • Revokes approval for implementation
  • Prevents new deployments using this implementation
Requirements:
  • Only callable by protocol admin
Use Cases:
  • Security issues discovered
  • Updated implementation available
  • Deprecated functionality

Remove Treasury Implementation

function removeTreasuryImplementation(
    bytes32 platformHash,
    uint256 implementationId
) external override onlyPlatformAdmin(platformHash);
Parameters:
  • platformHash: Platform identifier
  • implementationId: Implementation ID to remove
Effects:
  • Removes implementation registration from platform
  • Prevents new deployments
Requirements:
  • Only callable by platform admin

Treasury Deployment

Deploy Treasury

function deploy(
    bytes32 platformHash,
    address infoAddress,
    uint256 implementationId,
    string calldata name,
    string calldata symbol
) external override onlyPlatformAdmin(platformHash) returns (address clone);
Parameters:
  • platformHash: Platform identifier
  • infoAddress: CampaignInfo contract address
  • implementationId: Implementation to deploy
  • name: Treasury contract name
  • symbol: Treasury contract symbol
Returns:
  • Address of deployed treasury clone
Effects:
  • Creates new treasury contract using clone pattern
  • Initializes treasury with campaign info
  • Sets up platform configuration
Requirements:
  • Only callable by platform admin
  • Implementation must be approved
  • Campaign info address must be valid

Query Functions

Get Treasury Address

function getTreasuryAddress(
    bytes32 platformHash,
    uint256 implementationId
) external view override returns (address);
Parameters:
  • platformHash: Platform identifier
  • implementationId: Implementation ID
Returns:
  • Treasury implementation address

Check Implementation Approved

function checkImplementationApproved(address implementation) 
    external 
    view 
    override 
    returns (bool);
Parameters:
  • implementation: Implementation address to check
Returns:
  • True if implementation is approved

Events

TreasuryImplementationRegistered

event TreasuryImplementationRegistered(
    bytes32 indexed platformHash,
    uint256 indexed implementationId,
    address indexed implementation
);
Emitted when: Platform admin registers an implementation

TreasuryImplementationApproved

event TreasuryImplementationApproved(
    bytes32 indexed platformHash,
    uint256 indexed implementationId,
    address indexed implementation
);
Emitted when: Protocol admin approves an implementation

TreasuryImplementationDisapproved

event TreasuryImplementationDisapproved(address indexed implementation);
Emitted when: Protocol admin disapproves an implementation

TreasuryDeployed

event TreasuryDeployed(
    bytes32 indexed platformHash,
    address indexed treasuryAddress,
    address indexed infoAddress
);
Emitted when: New treasury is deployed

Errors

TreasuryFactoryUnauthorized

error TreasuryFactoryUnauthorized();
Emitted when: Unauthorized action attempted

TreasuryFactoryInvalidAddress

error TreasuryFactoryInvalidAddress();
Emitted when: Zero address provided

TreasuryFactoryImplementationNotSet

error TreasuryFactoryImplementationNotSet();
Emitted when: Implementation not registered

TreasuryFactoryImplementationNotSetOrApproved

error TreasuryFactoryImplementationNotSetOrApproved();
Emitted when: Implementation not approved for deployment

TreasuryFactoryTreasuryCreationFailed

error TreasuryFactoryTreasuryCreationFailed();
Emitted when: Treasury deployment fails

TreasuryFactoryTreasuryInitializationFailed

error TreasuryFactoryTreasuryInitializationFailed();
Emitted when: Treasury initialization fails

TreasuryFactorySettingPlatformInfoFailed

error TreasuryFactorySettingPlatformInfoFailed();
Emitted when: Setting platform info on campaign fails

Usage Examples

Platform Setup

// Platform admin registers implementation
const treasuryFactory = await ethers.getContractAt(
  'TreasuryFactory',
  treasuryFactoryAddress
);

const implementationAddress = '0x...'; // AllOrNothing contract
const implementationId = 1; // Platform-specific ID

await treasuryFactory.registerTreasuryImplementation(
  platformHash,
  implementationId,
  implementationAddress
);

Protocol Approval

// Protocol admin approves implementation
await treasuryFactory.approveTreasuryImplementation(
  platformHash,
  implementationId,
  { from: protocolAdmin }
);

Deploy Treasury for Campaign

// Deploy treasury for a campaign
const campaignInfoAddress = '0x...';
const name = 'Oak Campaign Treasury';
const symbol = 'OAK-CT';

const tx = await treasuryFactory.deploy(
  platformHash,
  campaignInfoAddress,
  implementationId,
  name,
  symbol
);

const receipt = await tx.wait();

// Extract treasury address from event
const treasuryAddress = receipt.events.find(
  e => e.event === 'TreasuryDeployed'
).args.treasuryAddress;

console.log('Treasury deployed:', treasuryAddress);

Check Implementation Status

// Check if implementation is approved
const approved = await treasuryFactory.checkImplementationApproved(
  implementationAddress
);

// Get implementation address
const implementation = await treasuryFactory.getTreasuryAddress(
  platformHash,
  implementationId
);

console.log('Approved:', approved);
console.log('Implementation:', implementation);

Complete Workflow

// 1. Platform registers implementation
await treasuryFactory.registerTreasuryImplementation(
  platformHash,
  implementationId,
  implementationAddress
);

// 2. Protocol admin reviews and approves
await treasuryFactory.approveTreasuryImplementation(
  platformHash,
  implementationId,
  { from: protocolAdmin }
);

// 3. Campaign creation triggers treasury deployment
const campaignFactory = await ethers.getContractAt(
  'CampaignInfoFactory',
  campaignFactoryAddress
);

const createTx = await campaignFactory.createCampaign(campaignData);
const campaignReceipt = await createTx.wait();

// 4. Platform deploys treasury for campaign
const treasuryAddress = await treasuryFactory.deploy(
  platformHash,
  campaignInfoAddress,
  implementationId,
  'My Campaign Treasury',
  'MCT'
);

// 5. Connect to treasury
const treasury = await ethers.getContractAt(
  'AllOrNothing',
  treasuryAddress
);

Security Considerations

Two-Stage Approval

  • Registration: Platform admin registers implementation
  • Approval: Protocol admin must approve before use
  • Review Process: Allows code review before production use
  • Deprecation: Can disapprove implementations with issues

Access Control

  • Platform Admin: Registers implementations, deploys treasuries
  • Protocol Admin: Approves implementations, can revoke approval
  • Separation of Concerns: Platform manages platform-level config, protocol manages security

Clone Pattern

  • Gas Efficiency: Minimal proxy pattern reduces deployment costs
  • Upgradeability: Implementation can be upgraded, existing clones use new logic
  • Consistency: All clones share same implementation code

Implementation Verification

  • Approval Required: Cannot deploy unapproved implementations
  • Audit Trail: All approvals/disapprovals logged via events
  • Quick Revocation: Can disapprove implementations immediately

Integration Notes

With CampaignInfoFactory

// Campaign factory calls treasury factory
// when creating campaigns

// 1. Create campaign
const campaignTx = await campaignFactory.createCampaign({
  creator,
  identifierHash,
  selectedPlatformHash,
  platformDataKey,
  platformDataValue,
  campaignData
});

// 2. Factory internally calls treasury factory
// to deploy treasuries for each platform

// 3. Platform managers treasury operations

With Treasury Contracts

// Treasury factory deploys clones
const treasuryClone = await treasuryFactory.deploy(...);

// Clone uses implementation logic
const treasury = new ethers.Contract(
  treasuryClone,
  AllOrNothingABI,
  signer
);

// All treasury operations work normally
await treasury.pledgeForAReward(rewardId, amount);

Event Monitoring

// Monitor approval events
treasuryFactory.on('TreasuryImplementationApproved', 
  (platformHash, implementationId, implementation, event) => {
    console.log('Implementation approved:', implementationId);
    
    // Update frontend to show as available
    updatePlatformImplementations(platformHash, implementationId);
  }
);

// Monitor deployment events
treasuryFactory.on('TreasuryDeployed', 
  (platformHash, treasuryAddress, infoAddress, event) => {
    console.log('New treasury:', treasuryAddress);
    
    // Index treasury for queries
    await indexTreasury(treasuryAddress, platformHash);
  }
);

Best Practices

Implementation Management

  • Test implementations thoroughly before registration
  • Use semantic versioning for implementation IDs
  • Document implementation differences and use cases
  • Keep approved implementations minimal

Platform Configuration

  • Use one implementation per funding model (AllOrNothing)
  • Reserve implementation ID 1 for default implementation
  • Use higher IDs for experimental or platform-specific models

Security

  • Regular security audits of implementations
  • Quick disapproval process for vulnerabilities
  • Monitor all deployment events
  • Maintain implementation registry off-chain

Upgrade Path

Updating Implementation

// 1. Deploy new implementation
const newImplementation = await deployNewTreasuryImplementation();

// 2. Register with same ID (overwrites)
await treasuryFactory.registerTreasuryImplementation(
  platformHash,
  implementationId,
  newImplementation
);

// 3. Protocol admin approves
await treasuryFactory.approveTreasuryImplementation(
  platformHash,
  implementationId
);

// 4. New deployments use updated implementation
// Existing clones remain on old version

Deprecation

// Disapprove old implementation
await treasuryFactory.disapproveTreasuryImplementation(
  oldImplementation
);

// New deployments will revert
// Existing treasuries continue operating

Next Steps