home / skills / multiversx / mx-ai-skills / mvx_factory_manager
This skill helps you deploy, track, and upgrade child contracts using a template-driven factory pattern for safer, scalable smart contract management.
npx playbooks add skill multiversx/mx-ai-skills --skill mvx_factory_managerReview the files below or copy the command above to add this skill to your agents.
---
name: mvx_factory_manager
description: Factory pattern for deploying and managing child contracts from a template.
---
# MultiversX Factory/Manager Pattern
Three core operations: Deploy, Track, Upgrade.
## Deploy
```rust
#[endpoint(deployChild)]
fn deploy_child(&self, child_id: ManagedBuffer, init_arg: BigUint) -> ManagedAddress {
let template = self.template_address().get();
let metadata = CodeMetadata::UPGRADEABLE | CodeMetadata::READABLE | CodeMetadata::PAYABLE;
let new_address = self.tx()
.typed(child_proxy::ChildProxy)
.init(init_arg)
.from_source(template)
.code_metadata(metadata)
.returns(ReturnsNewManagedAddress)
.sync_call();
self.child_addresses().insert(new_address.clone());
self.child_by_id(&child_id).set(new_address.clone());
new_address
}
```
## Track (Registry)
```rust
#[storage_mapper("templateAddress")]
fn template_address(&self) -> SingleValueMapper<ManagedAddress>;
#[storage_mapper("childAddresses")]
fn child_addresses(&self) -> SetMapper<ManagedAddress>;
#[storage_mapper("childById")]
fn child_by_id(&self, id: &ManagedBuffer) -> SingleValueMapper<ManagedAddress>;
#[storage_mapper("admins")]
fn admins(&self) -> UnorderedSetMapper<ManagedAddress>;
```
**Pattern**: SetMapper (iteration + contains) + SingleValueMapper (ID lookup).
## Upgrade
```rust
#[endpoint(upgradeChild)]
fn upgrade_child(&self, child_id: ManagedBuffer) {
self.require_admin();
let child = self.child_by_id(&child_id).get();
require!(self.child_addresses().contains(&child), "Not managed");
let metadata = CodeMetadata::UPGRADEABLE | CodeMetadata::READABLE | CodeMetadata::PAYABLE;
self.tx().to(child).typed(child_proxy::ChildProxy).upgrade()
.code_metadata(metadata)
.from_source(self.template_address().get())
.upgrade_async_call_and_exit();
}
```
## CodeMetadata
| Flag | Effect |
|---|---|
| `UPGRADEABLE` | Child can be upgraded (almost always needed) |
| `READABLE` | Other contracts can read storage |
| `PAYABLE` | Can receive EGLD directly |
## Anti-Patterns
- Deploying without tracking (can't upgrade later)
- Missing `UPGRADEABLE` flag
- Upgrading without validating address is a managed child
This skill implements a factory/manager pattern for deploying, tracking, and upgrading child contracts from a reusable template. It provides secure lifecycle operations so teams can spawn many upgradeable child instances while keeping a central registry and admin controls. The design emphasizes safe upgrades, readable storage, and payable children when required.
The skill deploys child contracts by calling a template as a source and storing returned addresses in a SetMapper and a SingleValueMapper keyed by ID. It enforces metadata flags like UPGRADEABLE, READABLE, and PAYABLE when deploying or upgrading so children behave as intended. Upgrade operations validate that the target address is managed and require admin privileges before performing an async upgrade call.
What CodeMetadata flags are mandatory?
UPGRADEABLE is almost always required if you plan to upgrade children. Add READABLE when other contracts must read child storage and PAYABLE only if children should accept EGLD directly.
How do I ensure only managed children are upgraded?
Store every deployed address in a SetMapper and check contains() before upgrade. Also enforce admin checks to prevent unauthorized upgrades.