home / skills / multiversx / mx-ai-skills / mvx_factory_manager

mvx_factory_manager skill

/antigravity/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_manager

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
2.2 KB
---
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

Overview

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.

How this skill works

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.

When to use it

  • You need to create many similar contracts from a single template and keep a reliable registry.
  • You must support future upgrades to deployed child contracts while retaining identity mapping by ID.
  • You want cross-contract reads or to allow children to receive funds directly.
  • You need admin-controlled lifecycle operations for child instances.
  • You want iteration over all managed children plus fast lookup by ID.

Best practices

  • Always record deployed child addresses in a persistent SetMapper to enable upgrades and audits.
  • Persist a mapping from business IDs to addresses with SingleValueMapper for deterministic lookups.
  • Set CodeMetadata flags: UPGRADEABLE for future upgrades, READABLE when external read access is required, and PAYABLE if children should accept funds.
  • Require and check admin authorization before upgrade operations and validate that the address is in the managed set.
  • Avoid deploying children without inserting them into the registry; untracked instances cannot be upgraded via the manager.

Example use cases

  • SaaS platform that deploys per-customer contract instances and later patches business logic via upgrades.
  • NFT minter factory where each collection is a child contract tracked by collection ID for royalties and metadata upgrades.
  • DeFi vault factory spawning isolated vaults for strategies while maintaining a central upgrade path.
  • On-chain games that deploy per-player or per-session contracts and need admin-controlled fixes or feature rollouts.

FAQ

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.