Skip to main content
Factory contracts are smart contracts that can deploy other smart contracts. This pattern enables powerful use cases like creating token contracts on demand, deploying user-specific contracts, or building contract templates.

Overview

A factory contract:
  • Stores the WASM code of contracts it can deploy
  • Creates new contract accounts
  • Deploys code to those accounts
  • Optionally initializes the deployed contracts

GitHub Repository

View the complete factory contract example

How it works

1

Store contract WASM

The factory stores the binary code of contracts it will deploy:
use near_sdk::{near, env, Promise, AccountId};
use near_sdk::store::Vector;

#[near(contract_state)]
pub struct Factory {
    code: Vec<u8>,
}

#[near]
impl Factory {
    #[init]
    pub fn new(code: Vec<u8>) -> Self {
        Self { code }
    }
    
    pub fn update_code(&mut self, code: Vec<u8>) {
        self.code = code;
    }
}
2

Create new accounts

The factory creates sub-accounts and deploys contracts to them:
#[near]
impl Factory {
    #[payable]
    pub fn create_contract(
        &self,
        name: String,
        args: Vec<u8>,
    ) -> Promise {
        let account_id: AccountId = format!(
            "{}.{}",
            name,
            env::current_account_id()
        )
        .parse()
        .unwrap();
        
        let attached_deposit = env::attached_deposit();
        
        Promise::new(account_id.clone())
            .create_account()
            .transfer(attached_deposit)
            .deploy_contract(self.code.clone())
            .function_call(
                "init".to_string(),
                args,
                0,
                Gas::from_tgas(30),
            )
    }
}
3

Deploy and test

# Deploy the factory
near contract deploy factory.testnet use-file ./factory.wasm

# Store the contract code to deploy
near contract call-function as-transaction factory.testnet \
  update_code \
  file-args contract.wasm \
  prepaid-gas '300 TeraGas' \
  attached-deposit '0 NEAR' \
  network-config testnet

# Create a new contract instance
near contract call-function as-transaction factory.testnet \
  create_contract \
  json-args '{"name":"my-contract","args":{}}' \
  prepaid-gas '300 TeraGas' \
  attached-deposit '3 NEAR' \
  network-config testnet

Use cases

Token factories

Deploy new FT or NFT contracts on demand for users or projects

DAO factories

Create DAO contracts with custom governance rules

Game instances

Spawn isolated game session contracts

User contracts

Deploy personal contracts for each user (e.g., wallets, vaults)

Best practices

Choose a clear naming convention for deployed contracts:
  • Use meaningful prefixes: token.factory.near
  • Include version numbers if needed: v1.token.factory.near
  • Consider uniqueness: append timestamps or counters
  • Sub-accounts cost storage, factor into deposit requirements
Creating accounts and deploying contracts requires NEAR deposits:
  • Account creation: ~0.00182 NEAR minimum
  • Code storage: ~0.0001 NEAR per byte
  • State storage: depends on contract initialization
  • Always require sufficient deposit in create_contract
Plan for updating the contract template:
  • Implement update_code with proper access control
  • Consider versioning: maintain multiple templates
  • Test thoroughly before updating production code
  • Document breaking changes
Protect your factory from abuse:
  • Limit who can create contracts (whitelist, fees, etc.)
  • Validate contract initialization parameters
  • Consider rate limiting
  • Monitor for suspicious patterns

Advanced patterns

Versioned deployments

Maintain multiple contract versions:
#[near(contract_state)]
pub struct Factory {
    versions: UnorderedMap<String, Vec<u8>>,
}

#[near]
impl Factory {
    pub fn add_version(&mut self, version: String, code: Vec<u8>) {
        self.versions.insert(version, code);
    }
    
    #[payable]
    pub fn create_contract_version(
        &self,
        version: String,
        name: String,
        args: Vec<u8>,
    ) -> Promise {
        let code = self.versions.get(&version).expect("Version not found");
        // ... deploy with specific version
    }
}

Access control

Restrict who can create contracts:
#[near(contract_state)]
pub struct Factory {
    owner: AccountId,
    whitelist: UnorderedSet<AccountId>,
}

#[near]
impl Factory {
    #[payable]
    pub fn create_contract(&self, name: String) -> Promise {
        let caller = env::predecessor_account_id();
        require!(
            self.whitelist.contains(&caller),
            "Not authorized to create contracts"
        );
        // ... create contract
    }
}

Callback tracking

Track deployed contracts:
#[near(contract_state)]
pub struct Factory {
    deployed_contracts: Vector<AccountId>,
}

#[near]
impl Factory {
    #[private]
    pub fn on_contract_created(&mut self, account_id: AccountId) {
        if env::promise_results_count() == 1 {
            match env::promise_result(0) {
                PromiseResult::Successful(_) => {
                    self.deployed_contracts.push(account_id);
                    log!("Contract deployed successfully");
                }
                _ => log!("Contract deployment failed"),
            }
        }
    }
    
    pub fn get_deployed_contracts(&self) -> Vec<AccountId> {
        self.deployed_contracts.iter().collect()
    }
}

Testing factory contracts

#[tokio::test]
async fn test_factory_deployment() -> Result<()> {
    let worker = near_workspaces::sandbox().await?;
    let factory_wasm = std::fs::read("factory.wasm")?;
    let contract_wasm = std::fs::read("contract.wasm")?;
    
    // Deploy factory
    let factory = worker.dev_deploy(&factory_wasm).await?;
    
    // Initialize with contract code
    factory
        .call("new")
        .args_borsh(contract_wasm.clone())
        .transact()
        .await?;
    
    // Create a new contract
    let outcome = factory
        .call("create_contract")
        .args_json(serde_json::json!({
            "name": "test-contract",
            "args": "{}"
        }))
        .deposit(near_sdk::NearToken::from_near(5))
        .transact()
        .await?;
    
    assert!(outcome.is_success());
    
    Ok(())
}

Next steps

Update contracts

Learn how to update deployed contracts

Cross-contract calls

Interact with deployed contracts

DAO primitives

Use factories to create DAOs

Contract standards

Implement standard interfaces

Build docs developers (and LLMs) love