TreasuryFactory
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
| Variable | Type | Description |
|---|---|---|
implementationMap | mapping(bytes32 => mapping(uint256 => address)) | Maps platform and implementation ID to implementation address |
ApprovedImplementations
| Variable | Type | Description |
|---|---|---|
approvedImplementations | mapping(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 identifierimplementationId: Unique ID for this implementationimplementation: 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 identifierimplementationId: 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 identifierimplementationId: 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 identifierinfoAddress: CampaignInfo contract addressimplementationId: Implementation to deployname: Treasury contract namesymbol: 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 identifierimplementationId: 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
- CampaignInfo - Campaign contract
- GlobalParams - Protocol configuration
- AllOrNothing - Treasury implementation
- BaseTreasury - Treasury base contract
- Platform Integration - Integration guide