A comprehensive TypeScript framework for deploying, upgrading, and managing ERC-2535 Diamond Proxy contracts with enterprise-grade features including OpenZeppelin Defender integration, sophisticated version management, and flexible deployment strategies.
- Full ERC-2535 Diamond Proxy Standard support
- Modular facet architecture with automated function selector management
- Smart collision detection and resolution
- Comprehensive state management and validation
- OpenZeppelin Defender Integration: Secure deployments through Defender's infrastructure
- Multi-signature Support: Gnosis Safe and custom multisig workflows
- Automated Verification: Contract verification on Etherscan and other explorers
- Access Control: Role-based deployment permissions
- Strategy Pattern: Pluggable deployment strategies (Local, Defender, Custom)
- Version Control: Sophisticated versioning for facets and protocols
- Upgrade Automation: Intelligent upgrade detection and execution
- Rollback Support: Safe rollback mechanisms
- Repository Pattern: Flexible data persistence (File-based, Database-ready)
- Configuration Management: JSON-based configuration with validation
- Comprehensive Testing: Unit, integration, and end-to-end test suites
- CLI Tools: Command-line interface for deployment operations
npm install @geniusventures/diamondsimport { Diamond, DiamondDeployer, FileDeploymentRepository } from '@geniusventures/diamonds';
import { LocalDeploymentStrategy } from '@geniusventures/diamonds/strategies';
import { ethers } from 'hardhat';
// Create diamond configuration
const config = {
diamondName: 'MyDiamond',
networkName: 'localhost',
chainId: 31337,
deploymentsPath: './diamonds',
contractsPath: './contracts'
};
// Setup diamond and deployment components
const repository = new FileDeploymentRepository(config);
const diamond = new Diamond(config, repository);
// Set provider and signer
diamond.setProvider(ethers.provider);
diamond.setSigner(await ethers.getSigners()[0]);
// Deploy using local strategy
const strategy = new LocalDeploymentStrategy(true); // verbose logging
const deployer = new DiamondDeployer(diamond, strategy);
await deployer.deployDiamond();diamonds/
βββ src/ # Source code
β βββ core/ # Core classes
β β βββ Diamond.ts # Main diamond management
β β βββ DiamondDeployer.ts # Deployment orchestration
β β βββ DeploymentManager.ts # Deployment lifecycle
β β βββ CallbackManager.ts # Post-deployment callbacks
β βββ strategies/ # Deployment strategies
β β βββ BaseDeploymentStrategy.ts
β β βββ LocalDeploymentStrategy.ts
β β βββ OZDefenderDeploymentStrategy.ts
β βββ repositories/ # Data persistence
β β βββ DeploymentRepository.ts
β β βββ FileDeploymentRepository.ts
β β βββ jsonFileHandler.ts
β βββ schemas/ # Zod validation schemas
β β βββ DeploymentSchema.ts
β βββ types/ # TypeScript definitions
β βββ utils/ # Utility functions
β βββ helpers/ # Helper functions
βββ docs/ # Documentation
βββ examples/ # Usage examples
βββ test/ # Test suites
βββ scripts/ # CLI and utility scriptsCreate a diamond configuration file (myDiamond.config.json):
{
"protocolVersion": 1.0,
"protocolInitFacet": "MyProtocolFacet",
"facets": {
"DiamondCutFacet": {
"priority": 10,
"versions": {
"1.0": {}
}
},
"DiamondLoupeFacet": {
"priority": 20,
"versions": {
"1.0": {}
}
},
"MyCustomFacet": {
"priority": 30,
"versions": {
"1.0": {
"deployInit": "initialize()",
"upgradeInit": "upgradeToV1()",
"callbacks": ["postDeployCallback"],
"deployInclude": ["0x12345678"],
"deployExclude": ["0x87654321"]
}
}
}
}
}# Network Configuration
NETWORK_NAME=sepolia
CHAIN_ID=11155111
RPC_URL=https://sepolia.infura.io/v3/YOUR_KEY
# OpenZeppelin Defender (Optional)
DEFENDER_API_KEY=your_api_key
DEFENDER_API_SECRET=your_api_secret
DEFENDER_RELAYER_ADDRESS=0x...
DEFENDER_SAFE_ADDRESS=0x...
# Deployment Options
AUTO_APPROVE_DEFENDER_PROPOSALS=false
VERBOSE_DEPLOYMENT=trueThe Diamonds module provides seamless integration with OpenZeppelin Defender for enterprise-grade deployments.
- Create Defender Account: Visit OpenZeppelin Defender
- Generate API Credentials: Create API keys with Deploy and Admin permissions
- Configure Environment: Set your API credentials in
.env
import { OZDefenderDeploymentStrategy } from '@geniusventures/diamonds/strategies';
const strategy = new OZDefenderDeploymentStrategy(
process.env.DEFENDER_API_KEY!,
process.env.DEFENDER_API_SECRET!,
process.env.DEFENDER_RELAYER_ADDRESS!,
false, // manual approval for production
process.env.DEFENDER_SAFE_ADDRESS!,
'Safe'
);
const deployer = new DiamondDeployer(diamond, strategy);
await deployer.deployDiamond();- Secure Deployments: All deployments go through Defender's secure infrastructure
- Multi-signature Support: Integrate with Gnosis Safe for production deployments
- Automated Monitoring: Real-time deployment tracking and status updates
- Gas Optimization: Automatic gas price optimization and retry logic
For development and testing:
import { LocalDeploymentStrategy } from '@geniusventures/diamonds/strategies';
const strategy = new LocalDeploymentStrategy(true); // verbose loggingFor production deployments:
import { OZDefenderDeploymentStrategy } from '@geniusventures/diamonds/strategies';
const strategy = new OZDefenderDeploymentStrategy(
apiKey,
apiSecret,
relayerAddress,
autoApprove,
viaAddress,
viaType,
verbose
);Implement your own deployment strategy:
import { BaseDeploymentStrategy } from '@geniusventures/diamonds/strategies';
export class CustomDeploymentStrategy extends BaseDeploymentStrategy {
protected async deployDiamondTasks(diamond: Diamond): Promise<void> {
// Custom deployment logic
}
protected async performDiamondCutTasks(diamond: Diamond): Promise<void> {
// Custom diamond cut logic
}
}The Diamonds module provides sophisticated version management:
{
"facets": {
"MyFacet": {
"priority": 100,
"versions": {
"1.0": {
"deployInit": "initialize()",
"upgradeInit": "upgradeToV1()"
},
"2.0": {
"deployInit": "initialize()",
"upgradeInit": "upgradeToV2()",
"fromVersions": [1.0]
}
}
}
}
}Automatic function selector management with collision detection:
- Priority-based Resolution: Higher priority facets take precedence
- Include/Exclude Lists: Fine-grained control over function selectors
- Collision Detection: Automatic detection and resolution of selector conflicts
- Orphaned Selector Prevention: Validation to prevent deployment issues
Execute custom logic after deployment:
// In your callbacks directory
export async function postDeployCallback(args: CallbackArgs) {
const { diamond } = args;
console.log(`Post-deployment callback executed for ${diamond.diamondName}`);
// Custom post-deployment logic
await customInitialization();
}# Install dependencies
npm install
# Run all tests
npm test
# Run unit tests only
npm run test:unit
# Run integration tests
npm run test:integration
# Run with coverage
npm run test:coverage
# Test specific network
TEST_NETWORK=sepolia npm test- Unit Tests: Individual component testing
- Integration Tests: Component interaction testing
- Defender Integration: End-to-end Defender testing
- Performance Tests: Deployment speed and resource usage
describe('Diamond Deployment', () => {
let diamond: Diamond;
let strategy: LocalDeploymentStrategy;
beforeEach(() => {
const config = {
diamondName: 'TestDiamond',
networkName: 'hardhat',
chainId: 31337,
deploymentsPath: './test-diamonds',
contractsPath: './contracts'
};
const repository = new FileDeploymentRepository(config);
diamond = new Diamond(config, repository);
strategy = new LocalDeploymentStrategy();
});
it('should deploy diamond successfully', async () => {
const deployer = new DiamondDeployer(diamond, strategy);
await deployer.deployDiamond();
const deployedData = diamond.getDeployedDiamondData();
expect(deployedData.DiamondAddress).to.not.be.undefined;
});
});The Diamonds module includes a comprehensive CLI for deployment management:
# Install CLI globally
npm install -g @geniusventures/diamonds
# Deploy a diamond
diamonds deploy --diamond MyDiamond --network sepolia
# Upgrade a diamond
diamonds upgrade --diamond MyDiamond
# Check deployment status
diamonds status --diamond MyDiamond
# Verify contracts
diamonds verify --diamond MyDiamond
# Initialize new project
diamonds init --diamond MyNewDiamond --network mainnet--diamond <name>: Diamond name--network <name>: Target network--config <path>: Configuration file path--auto-approve: Auto-approve Defender proposals--verbose: Verbose output--batch <path>: Batch deployment configuration
import { Diamond, DiamondDeployer, FileDeploymentRepository } from '@geniusventures/diamonds';
import { LocalDeploymentStrategy } from '@geniusventures/diamonds/strategies';
async function deployBasicDiamond() {
const config = {
diamondName: 'BasicDiamond',
networkName: 'localhost',
chainId: 31337,
deploymentsPath: './diamonds',
contractsPath: './contracts'
};
const repository = new FileDeploymentRepository(config);
const diamond = new Diamond(config, repository);
diamond.setProvider(ethers.provider);
diamond.setSigner(await ethers.getSigners()[0]);
const strategy = new LocalDeploymentStrategy();
const deployer = new DiamondDeployer(diamond, strategy);
await deployer.deployDiamond();
console.log('Diamond deployed successfully!');
}import { OZDefenderDeploymentStrategy } from '@geniusventures/diamonds/strategies';
async function deployProductionDiamond() {
const config = {
diamondName: 'ProductionDiamond',
networkName: 'mainnet',
chainId: 1,
deploymentsPath: './diamonds',
contractsPath: './contracts'
};
const repository = new FileDeploymentRepository(config);
const diamond = new Diamond(config, repository);
// Setup provider and signer for mainnet
diamond.setProvider(mainnetProvider);
diamond.setSigner(productionSigner);
const strategy = new OZDefenderDeploymentStrategy(
process.env.DEFENDER_API_KEY!,
process.env.DEFENDER_API_SECRET!,
process.env.DEFENDER_RELAYER_ADDRESS!,
false, // manual approval for production
process.env.DEFENDER_SAFE_ADDRESS!,
'Safe'
);
const deployer = new DiamondDeployer(diamond, strategy);
await deployer.deployDiamond();
}async function performComplexUpgrade() {
// Load existing diamond
const diamond = await loadExistingDiamond('MyDiamond');
// Update configuration for new version
const config = diamond.repository.loadDeployConfig();
config.protocolVersion = 2.0;
// Add new facet
config.facets.NewFeatureFacet = {
priority: 150,
versions: {
"2.0": {
deployInit: "initialize()",
callbacks: ["setupNewFeature"]
}
}
};
// Upgrade existing facet
config.facets.ExistingFacet.versions["2.0"] = {
upgradeInit: "upgradeToV2()",
fromVersions: [1.0]
};
await diamond.repository.saveDeployConfig(config);
// Execute upgrade
const strategy = new OZDefenderDeploymentStrategy(/* config */);
const deployer = new DiamondDeployer(diamond, strategy);
await deployer.deployDiamond();
}const strategy = new LocalDeploymentStrategy(true); // Enable verbose modeimport { getSighash } from '@geniusventures/diamonds/utils';
// Get function selector
const selector = getSighash('transfer(address,uint256)');
console.log('Selector:', selector);
// Check if selector is registered
const isRegistered = diamond.isFunctionSelectorRegistered(selector);
console.log('Is registered:', isRegistered);// Check deployment status
const deployedData = diamond.getDeployedDiamondData();
console.log('Diamond address:', deployedData.DiamondAddress);
console.log('Deployed facets:', Object.keys(deployedData.DeployedFacets || {}));
// Validate on-chain state
import { diffDeployedFacets } from '@geniusventures/diamonds/utils';
const isConsistent = await diffDeployedFacets(deployedData, ethers.provider, true);- Use Multi-signature Wallets: Always use multi-sig for mainnet deployments
- Test Thoroughly: Test all upgrades on testnets first
- Verify Contracts: Ensure all contracts are verified on Etherscan
- Monitor Deployments: Use Defender monitoring for production systems
- Access Control: Implement proper role-based access controls
// Production configuration example
const productionConfig = {
diamondName: 'ProductionDiamond',
networkName: 'mainnet',
chainId: 1,
deploymentsPath: './production-diamonds',
contractsPath: './contracts',
writeDeployedDiamondData: true
};
const strategy = new OZDefenderDeploymentStrategy(
process.env.PROD_DEFENDER_API_KEY!,
process.env.PROD_DEFENDER_API_SECRET!,
process.env.PROD_RELAYER_ADDRESS!,
false, // Never auto-approve in production
process.env.PROD_SAFE_ADDRESS!,
'Safe'
);We welcome contributions! Please see our Contributing Guide for details.
# Clone the repository
git clone https://github.com/geniusventures/diamonds.git
cd diamonds
# Install dependencies
npm install
# Run tests
npm test
# Build the project
npm run build
# Run linting
npm run lint- Follow TypeScript best practices
- Maintain 90%+ test coverage
- Use conventional commit messages
- Update documentation for new features
- Add comprehensive tests for new functionality
This project is licensed under the MIT License - see the LICENSE file for details.
- OpenZeppelin for Defender platform and security tools
- ERC-2535 Diamond Standard authors
- Hardhat development framework
- The Ethereum community for continuous innovation
- Documentation: Full Documentation
- GitHub Issues: Report Issues
- Discord: Join our Community
- Email: support@geniusventures.com
Built with β€οΈ for the Ethereum ecosystem by Genius Ventures