IFIFFactory Contract
The IFIFFactory contract serves as the central deployment and management hub for the IFIF ecosystem. It implements a clone-based deployment pattern for gas-efficient project creation and manages shared protocol resources including implementation contracts, whitelists, and DEX integration.
Overview
Contract Address: contracts/src/utils/IFIFFactory.sol
License: GPL-3.0-only
Solidity Version: 0.8.19
Key Features
- Clone-Based Deployment: Gas-efficient project deployment using LibClone deterministic patterns
- Mandatory Deployment Fees: Configurable fee collection in ETH or ERC20 tokens for all deployments
- Implementation Management: Centralized control of IFIF and token contract implementations
- Shared Resource Management: Unified whitelist, DEX router, and metadata configuration
- Role-Based Access Control: Hierarchical permissions for administrative functions
- Project Lifecycle Control: Stage transition validation and project finalization
- Token Deployment: Automated token contract creation and minting for successful projects
Core Components
Implementation Contracts
IFIF Implementation
address public implementation;- Purpose: Master contract for IFIF project clones
- Management: Updated by admin role for protocol upgrades
- Usage: Template for all new project deployments
Token Implementation
address public tokenImplementation;- Purpose: Master contract for project token deployments
- Management: Updated by admin role for token upgrades
- Usage: Template for successful project token creation
Shared Resources
Whitelist Contract
address public whitelist;- Purpose: Merkle tree-based access control for all projects
- Scope: Shared across entire protocol
- Management: Updated by admin role
DEX Router
address public dexRouter;- Purpose: Automated market making and liquidity provision
- Integration: Used by projects for DEX pair creation
- Management: Updated by admin role
Base URI
string public baseURI;- Purpose: NFT metadata base URL for all projects
- Format:
{baseURI}/{projectId}/{tokenId} - Management: Updated by admin role
Deployment Fees
mapping(address token => uint256 feeAmount) public deploymentFees;- Purpose: Maps payment tokens to required deployment fee amounts
- Configuration: Set by admin role for each supported payment token
- Payment: Use address(0) for ETH fees, token addresses for ERC20 fees
- Requirement: All deployments must pay configured fee - no free deployments allowed
Core Functions
Project Deployment
deploy()
function deploy(
IIFIF.Config calldata config,
IIFIF.NextConfig calldata nextConfig,
bytes calldata configSignature,
bytes calldata nextConfigSignature,
string calldata projectName,
string calldata projectSymbol,
address paymentToken
) external payable returns (address)Purpose: Deploys a new IFIF project using the clone pattern with EIP-712 signature validation and mandatory fee collection.
Parameters:
config: Core project configuration (funding targets, timings, token parameters)nextConfig: Mutable configuration (stakeholders, fees, pricing)configSignature: EIP-712 signature for config validationnextConfigSignature: EIP-712 signature for nextConfig validationprojectName: Human-readable name for project and NFT collectionprojectSymbol: Short symbol identifier for projectpaymentToken: Token address to pay deployment fee with (address(0) for ETH)
Access: Public payable function (signature validation provides security)
Process:
- Validates project ID is not already deployed
- Validates implementation contract is available
- Collects mandatory deployment fee in specified payment token
- Creates deterministic clone using LibClone
- Initializes project with provided configuration and signatures
- Registers project in deployment tracking
- Emits Deployed and DeploymentFeeCollected events
Returns: Address of newly deployed project contract
Fee Requirements:
- ETH Payment: Call with
{value: deploymentFee}whenpaymentTokenis address(0) - Token Payment: Approve factory for token transfer, call with
msg.value = 0 - Mandatory: Fee must be configured and paid - no free deployments allowed
Validations:
- Project ID uniqueness
- Implementation availability
- Valid EIP-712 signatures for both config structs
- Deployment fee configured and sufficient payment provided
Project Management
mintToken()
function mintToken(uint256 mintAmount) external returns (address)Purpose: Creates token contract and mints tokens for successful projects during deposit phase.
Parameters:
mintAmount: Amount of tokens to mint for distribution and liquidity
Access: Restricted to deployed project contracts only
Process:
- Validates caller is a deployed project
- Validates token implementation is available
- Creates deterministic clone of token implementation (first call only)
- Initializes token with project as minter (first call only)
- Mints additional tokens for subsequent distributor deposits
- Updates deployment details with token address
- Emits TokenDeployed and TokenMinted events
Returns: Address of the project's token contract
Usage: Called internally by project contracts during the deposit phase when distributors provide tokens for rewards and liquidity
updateDeploymentDetails()
function updateDeploymentDetails(
uint256 projectId,
string memory projectName,
string memory projectSymbol
) externalPurpose: Updates project name and symbol during INIT stage.
Parameters:
projectId: Unique project identifierprojectName: New project nameprojectSymbol: New project symbol
Access: Restricted to project owner during INIT stage only
Usage: Allows project owner to modify metadata before sales begin
View Functions
Core Configuration
implementation() → address
Returns the current project implementation contract address used for cloning new projects.
tokenImplementation() → address
Returns the current project token implementation contract address used for deploying project tokens.
whitelist() → address
Returns the whitelist contract address used for sale access control.
dexRouter() → address
Returns the DEX router contract address used for liquidity operations.
baseURI() → string
Returns the base URI for NFT metadata across all projects.
Role Management
getRoleHelper() → address
Returns the current role helper contract address that implements access control functionality. Inherited from the IRole interface.
Deployment Information
deployments(uint256 projectId) → address
Returns the project contract address for a given project ID.
Parameters:
projectId: Unique project identifier
Returns: Address of the deployed project contract
deploymentDetails(address project) → (uint256, address, address, bool, string, string)
Returns detailed deployment information for a project.
Parameters:
project: Address of the deployed project contract
Returns:
id: Unique project identifiercurrentImplementation: Implementation contract used for deploymenttoken: Address of project token (if deployed)isDeployed: Whether the project has been deployedname: Human-readable project namesymbol: Short project symbol
ERC165 Support
supportsInterface(bytes4 interfaceId) → bool
Checks if the contract implements a specific interface ID.
Parameters:
interfaceId: The interface identifier as defined in ERC165
Returns: True if the contract implements the queried interface
Note: Supports IIFIFFactory and IRole interfaces
Administrative Functions
updateCore()
function updateCore(
address _whitelist,
address _dexRouter,
address _roles
) external onlyAdminPurpose: Updates core system contracts shared across all projects.
Parameters:
_whitelist: New whitelist contract address_dexRouter: New DEX router address_roles: New role management contract address
Access: Restricted to ADMIN_ROLE holders
Validations:
- Non-zero addresses for all parameters
- Emits CoreUpdated event
updateImplementation()
function updateImplementation(address newImplementation) external onlyAdminPurpose: Updates the IFIF implementation contract for new deployments.
Parameters:
newImplementation: Address of new IFIF implementation
Access: Restricted to ADMIN_ROLE holders
Validations:
- Non-zero address
- Contract implements IIFIF interface
- Emits ImplementationUpdated event
updateTokenImplementation()
function updateTokenImplementation(address newTokenImplementation) external onlyAdminPurpose: Updates the token implementation for new token deployments.
Parameters:
newTokenImplementation: Address of new token implementation
Access: Restricted to ADMIN_ROLE holders
Validations:
- Non-zero address
- Contract implements IIFIFToken interface
- Emits TokenImplementationUpdated event
updateBaseURI()
function updateBaseURI(string calldata newBaseURI) external onlyAdminPurpose: Updates the base URI for NFT metadata across all projects.
Parameters:
newBaseURI: New base URI string
Access: Restricted to ADMIN_ROLE holders
Emits: BaseURIUpdated event
updateDeploymentFee()
function updateDeploymentFee(address paymentToken, uint256 feeAmount) external onlyAdminPurpose: Sets or updates the deployment fee for a specific payment token.
Parameters:
paymentToken: Token address to set fee for (address(0) for ETH)feeAmount: Fee amount required for deployment in the specified token
Access: Restricted to ADMIN_ROLE holders
Usage:
- Configure ETH fee:
updateDeploymentFee(address(0), ethFeeAmount) - Configure token fee:
updateDeploymentFee(tokenAddress, tokenFeeAmount) - Remove fee:
updateDeploymentFee(tokenAddress, 0)(disables deployment with that token)
Emits: DeploymentFeeUpdated event
updateRoleHelper()
function updateRoleHelper(address roleHelper) external onlyAdminPurpose: Updates the role helper contract that implements access control functionality.
Parameters:
roleHelper: Address of new role helper contract implementing IAccessControl
Access: Restricted to ADMIN_ROLE holders
Validations:
- Non-zero address
- Contract implements IAccessControl interface
- Emits RoleHelperUpdated event
Note: Inherited from the Role contract, provides centralized role management
upgradeDeployment()
function upgradeDeployment(uint256 projectId, bytes calldata data) external onlyAdminPurpose: Upgrades a deployed project to a new implementation using UUPS pattern.
Parameters:
projectId: Unique project identifier to upgradedata: Optional initialization data for the new implementation
Access: Restricted to ADMIN_ROLE holders
Requirements:
- Project must be in INIT stage (upgrades not allowed during active sales or claim)
Process: Performs UUPS upgrade on the specified project contract
call()
function call(uint256 projectId, bytes calldata data, uint256 value) external onlyManager returns (bytes memory)Purpose: Executes arbitrary function calls on deployed project contracts for administrative operations.
Parameters:
projectId: Unique identifier of the target project contractdata: Encoded function call data to execute on the projectvalue: ETH value to send with the call (for payable functions)
Access: Restricted to MANAGER_ROLE holders
Returns: Return data from the executed function call
Usage: Emergency actions, configuration updates, or privileged operations requiring factory authority
withdraw()
function withdraw(address token, uint256 amount) external onlyAdminPurpose: Withdraws accumulated fees and tokens from the factory contract.
Parameters:
token: Address of the ERC20 token to withdraw (or address(0) for ETH)amount: Amount of tokens/ETH to withdraw to admin address
Access: Restricted to ADMIN_ROLE holders
Usage: Treasury management, fee collection, emergency fund recovery
Emits: Withdrew event
Query Functions
deployments()
function deployments(uint256 projectId) external view returns (address)Purpose: Retrieves project contract address by ID.
Parameters:
projectId: Unique project identifier
Returns: Project contract address or zero address if not found
deploymentDetails()
function deploymentDetails(address project) external view returns (
uint256 id,
address currentImplementation,
address token,
bool isDeployed,
string memory name,
string memory symbol
)Purpose: Retrieves detailed deployment information for a project.
Parameters:
project: Project contract address
Returns: Complete deployment struct with all project metadata
deploymentFees()
function deploymentFees(address token) external view returns (uint256)Purpose: Retrieves the deployment fee for a specific payment token.
Parameters:
token: Token address to query fee for (address(0) for ETH)
Returns: Fee amount required for deployment in the specified token
Core Resource Getters
function implementation() external view returns (address);
function tokenImplementation() external view returns (address);
function whitelist() external view returns (address);
function dexRouter() external view returns (address);
function baseURI() external view returns (string memory);Purpose: Access current core system contract addresses and configuration.
DEX Integration
The IFIFFactory provides infrastructure for DEX integration but does not automatically handle liquidity provision. Projects handle their own DEX interactions through the shared DEX router.
Shared DEX Router
The factory maintains a reference to a DEX router contract that projects can use for:
- Token Trading: Creating trading pairs for project tokens
- Liquidity Operations: Adding/removing liquidity as needed
- Price Discovery: Market-based token pricing mechanisms
Integration Notes
- Automatic Process: Projects automatically create DEX pairs and add liquidity during token deposit
- Shared Resource: All projects use the same DEX router configuration
- Standardized Integration: Consistent DEX integration across all projects
Security Architecture
Access Control Hierarchy
ADMIN_ROLE
├── Update implementation contracts
├── Update core system contracts (whitelist, DEX router, roles)
├── Manage base URI configuration
├── Configure deployment fees for different payment tokens
├── Upgrade deployed projects
└── Withdraw accumulated fees and tokens from factory
MANAGER_ROLE
├── Execute arbitrary function calls on deployed project contracts
├── Validate EIP-712 signatures for project configuration
├── Update whitelist merkle tree roots
└── Required for project initialization and config updates
DISTRIBUTOR_ROLE
├── Required for project distributors during initialization
├── Validated during project configuration
└── Enables deposit functionality in project contractsDeployment Security
- Deterministic Addresses: CREATE2 pattern for predictable deployments
- Implementation Validation: Ensures implementation contracts meet interface requirements
- Parameter Validation: Comprehensive validation of all deployment parameters
- Access Control: Role-based restrictions on critical functions
Upgrade Safety
- UUPS Pattern: Implementation contracts use UUPS upgradeable pattern
- Centralized Control: Factory manages upgrades for all deployed projects
- Validation Checks: Ensures upgrade safety and compatibility
Events
Core Events
event Deployed(uint256 indexed projectId, address indexed project);
event TokenDeployed(uint256 indexed projectId, address indexed token);
event TokenMinted(uint256 indexed projectId, uint256 amount);
event ImplementationUpdated(address indexed newImplementation);
event TokenImplementationUpdated(address indexed newTokenImplementation);
event CoreUpdated(address indexed newWhitelist, address indexed newDexRouter);
event DeploymentDetailsUpdated(uint256 indexed projectId, string newProjectName, string newProjectSymbol);
event BaseURIUpdated(string newBaseURI);
event DeploymentFeeUpdated(address indexed paymentToken, uint256 feeAmount);
event DeploymentFeeCollected(uint256 indexed projectId, address indexed payer, address indexed paymentToken, uint256 amount);
event Withdrew(address indexed to, address indexed token, uint256 amount);Integration Patterns
Project Deployment Flow
// Deploy new project with manager signatures and deployment fee
const ethFee = await factory.deploymentFees(ethers.constants.AddressZero);
const deployTx = await factory.deploy(
config, // Core configuration
nextConfig, // Mutable configuration
configSignature, // EIP-712 signature for config from manager
nextConfigSignature, // EIP-712 signature for nextConfig from manager
"Project Name", // Project name
"PROJ", // Project symbol
ethers.constants.AddressZero, // Payment token (address(0) for ETH)
{ value: ethFee } // Pay deployment fee in ETH
);
// Or deploy with ERC20 token fee
const tokenFee = await factory.deploymentFees(tokenAddress);
await token.approve(factory.address, tokenFee);
const deployTx = await factory.deploy(
config,
nextConfig,
configSignature,
nextConfigSignature,
"Project Name",
"PROJ",
tokenAddress // Payment token address
// No value needed for token payments
);
// Get deployed project address from event
const receipt = await deployTx.wait();
const deployedEvent = receipt.events.find(e => e.event === 'Deployed');
const projectAddress = deployedEvent.args.project;Token Deployment and Minting (Called by Project)
// Project contract calls factory to mint tokens during deposit phase
// This happens automatically when distributors deposit tokens
const project = await ethers.getContractAt("IFIF", projectAddress);
// Token creation and minting happens automatically during project.deposit()
// First deposit creates the token, subsequent deposits mint additional tokens
// Get token address from factory deployment details
const details = await factory.deploymentDetails(projectAddress);
const tokenAddress = details.token;
const tokenContract = await ethers.getContractAt("IIFIFToken", tokenAddress);Project Upgrade
// Admin upgrades project implementation
const upgradeTx = await factory.upgradeDeployment(
projectId,
"0x" // Optional initialization data
);Gas Optimization
Clone Pattern Benefits
- Deployment Cost: ~90% reduction compared to full contract deployment
- Deterministic Addresses: CREATE2 for predictable project addresses
- Shared Logic: Implementation reused across all projects
Storage Efficiency
- Minimal Storage: Factory stores only essential project metadata
- Delegated Storage: Project-specific data stored in individual contracts
- Shared Resources: Common resources shared across all projects
Testing Coverage
The IFIFFactory contract maintains comprehensive test coverage:
- Deployment scenarios: Valid and invalid project deployments
- Access control: Role-based permission testing
- Finalization logic: Success and failure path validation
- Address prediction: Deterministic address verification
- Administrative functions: Implementation and resource updates
- Edge cases: Boundary conditions and error scenarios
- Integration tests: End-to-end deployment and finalization flows
Deployment Configuration
Network-Specific Settings
// Example deployment configuration
const factoryConfig = {
roles: "0x...", // Roles contract address
whitelist: "0x...", // Whitelist contract address
dexRouter: "0x...", // DEX router address
baseURI: "https://api.ifif.io/metadata",
implementations: {
ifif: "0x...", // IFIF implementation
token: "0x..." // Token implementation
},
deploymentFees: {
eth: ethers.utils.parseEther("0.01"), // ETH fee amount
usdc: ethers.utils.parseUnits("10", 6), // USDC fee amount
// Add other supported payment tokens
}
};
// Configure deployment fees after factory deployment
await factory.updateDeploymentFee(ethers.constants.AddressZero, factoryConfig.deploymentFees.eth);
await factory.updateDeploymentFee(usdcAddress, factoryConfig.deploymentFees.usdc);Upgrade Considerations
- Implementation Updates: Test thoroughly before updating implementations
- Backwards Compatibility: Ensure new implementations maintain interface compatibility
- Migration Planning: Consider migration strategies for existing projects
For detailed deployment instructions and configuration examples, see the Deployment Guide.