Opals V2 Recipe
OpalsRecipe is a factory wrapper that deploys and wires nine interconnected contracts atomically. The createProject function handles deployment, initialization, and cross-contract wiring in a single transaction.
Contract Deployments
The recipe clones these templates from OpalsFactory:
Project - Coordination hub with bidirectional mappings
Token - ERC20 with fixed supply (1e27)
Operator - Role-based access control
LiquidityLauncher - OpalSwap liquidity deployment
PresaleCard - ERC721 for ownership
VaultCard - ERC721 for LP staking
PatronClaim - Permanent LP allocation (10x PatronPower)
VaultClaim - Flexible LP staking (1.024x-10x multipliers)
Distributor - Fee distribution to claims
ProjectCreationArgs
struct ProjectCreationArgs {
address owner; // Project owner address
string projectName; // Project display name
string tokenName; // ERC20 token name
string tokenSymbol; // ERC20 token symbol
string projectImageURI; // Project metadata URI
string projectDescriptorURI; // Project descriptor URI
uint256 tokenInitialSupply; // Total token supply (1e27 default)
uint256 launcherWethReserve; // Initial WETH for LP
uint256 launcherTokenReserve; // Initial tokens for LP
uint256 launcherTokenPriceInWei; // Token price in wei
address launcherTrigger; // Address authorized to trigger launch
uint256 launcherTarget; // ETH threshold for auto-launch
string patronCardImageURI; // Patron card metadata
string patronCardDescriptorURI; // Patron card descriptor
string patronCardBaseURI; // Patron card base URI
string vaultCardImageURI; // Vault card metadata
string vaultCardDescriptorURI; // Vault card descriptor
string vaultCardBaseURI; // Vault card base URI
}Deployment Flow
Phase 1: Deploy Core Components
_deployCoreComponents(args)Clones and partially initializes:
Project (deployed but initialized later)
Token (initialized with 1e27 supply minted to recipe)
LiquidityLauncher (deployed but initialized later)
Operator (initialized with project and owner)
Phase 2: Deploy Cards and Claims
_deployAndInitCardsAndClaims(args, result)Clone PatronCard, VaultCard, PatronClaim, VaultClaim templates
Initialize cards with naming convention:
{tokenName} Patron Card/{tokenSymbol}_PCInitialize PatronClaim with initial card set (patronCard address)
Now initialize Launcher with PatronClaim as
lpRecipientInitialize VaultClaim with VaultCard as minter
Clone and initialize Distributor with claim addresses
Now initialize Project with Distributor address
Grant operator permissions to claims
Add patronCard to PatronClaim with weight-based allocation (100 weight/card, 1000 max)
Phase 3: Wire Components
IProject(result.project).batchWireProject(
result.patronClaim,
result.vaultClaim,
result.patronCard,
result.vaultCard
)Establishes bidirectional mappings in Project hub:
Claim ↔ Card relationships
Component registry
Phase 4: Transfer Tokens
IERC20(result.token).safeTransfer(result.launcher, LIQUIDITY_SUPPLY); // 1e26
IERC20(result.token).safeTransfer(result.project, TOKEN_SUPPLY - LIQUIDITY_SUPPLY); // 9e26Launcher receives 20% (1e26 tokens) for liquidity
Project receives 80% (9e26 tokens) for distribution
Initialization Dependencies
Order matters due to circular dependencies:
Token and Operator initialize first (no dependencies)
PatronClaim needs to exist before Launcher initializes
Distributor needs PatronClaim and VaultClaim addresses
Project needs Distributor address for initialization
Constants
uint256 TOKEN_SUPPLY = 1e27; // 1 billion with 18 decimals
uint256 LIQUIDITY_SUPPLY = 1e26; // 100 million (10% of supply)
uint256 MAX_TOKEN_SUPPLY = 1e30; // Maximum to prevent overflowReturn Value
struct ProjectCreationResult {
address project; // Project coordination hub
address token; // ERC20 token
address launcher; // Liquidity launcher
address distributor; // Fee distributor
address operator; // Access control
address patronClaim; // Permanent claim
address vaultClaim; // Flexible claim
address patronCard; // Patron NFT
address vaultCard; // Vault NFT
}Security Properties
Atomic Deployment: All contracts deploy or none deploy
No Partial State: Transaction reverts on any failure
Immutable Masters: Clones reference audited templates
Validation: Input parameters validated before deployment
Usage Example
ProjectCreationArgs memory args = ProjectCreationArgs({
owner: msg.sender,
projectName: "Example Project",
tokenName: "Example Token",
tokenSymbol: "TKN",
projectImageURI: "ipfs://...",
projectDescriptorURI: "ipfs://...",
tokenInitialSupply: 1e27,
launcherWethReserve: 0,
launcherTokenReserve: 0,
launcherTokenPriceInWei: 0,
launcherTrigger: address(this),
launcherTarget: 100 ether,
patronCardImageURI: "ipfs://...",
patronCardDescriptorURI: "ipfs://...",
patronCardBaseURI: "ipfs://...",
vaultCardImageURI: "ipfs://...",
vaultCardDescriptorURI: "ipfs://...",
vaultCardBaseURI: "ipfs://..."
});
ProjectCreationResult memory result = recipe.createProject(args);All nine contracts deployed, initialized, and wired in one transaction. For automatically uploading images to IPFS, please use the create project wizard at https://opals.io/
Last updated