Creating smart contracts that can deploy other contracts is a powerful feature in Solidity. This pattern, known as the contract factory, enables developers to dynamically instantiate new contract instances based on a predefined template. It's widely used across decentralized finance (DeFi), NFT platforms, and token launch tools.
In this guide, we’ll explore how to use Solidity’s new keyword to create a contract factory, understand its inner workings, and walk through a complete implementation with testing using HardHat. Whether you're building liquidity pools or enabling users to mint personalized tokens, mastering this concept is essential for scalable dApp development.
Understanding the Contract Factory Pattern
A contract factory is a design pattern where one smart contract (the factory) deploys multiple instances of another contract (the template). Each deployed instance inherits the logic of the template but can have unique state variables initialized at deployment time.
This approach offers several advantages:
- Efficiency: Deploy the factory once and generate unlimited child contracts.
- Customization: Allow users to set parameters during creation (e.g., ownership, initial values).
- Scalability: Ideal for platforms that need user-generated contracts without manual deployment.
👉 Discover how blockchain developers streamline contract deployment workflows.
Common Use Cases
The factory pattern powers many real-world applications:
- DeFi protocols like Uniswap use factories to create trading pairs automatically.
- NFT mints enforce per-wallet limits by generating user-specific contracts.
- No-code platforms let non-developers launch custom tokens via intuitive interfaces.
- Enterprise solutions apply it to business process automation and secure medical record systems.
These examples highlight the flexibility and reusability enabled by dynamic contract creation.
Core Implementation: Building a Bank Factory
Let’s build a simple yet functional example — a BankFactory that creates Bank contracts. Each bank will have:
- An owner
- Initial funds
- A reference to the deployer (the factory)
Step 1: Define the Template – The Bank Contract
This is the blueprint used for every new instance:
contract Bank {
uint256 public bank_funds;
address public owner;
address public deployer;
constructor(address _owner, uint256 _funds) {
bank_funds = _funds;
owner = _owner;
deployer = msg.sender; // This will be the factory address
}
}When a new Bank is created, it stores:
_fundsas its initial balance_owneras the designated ownermsg.sender(the factory) as the deployer
Step 2: Build the Factory – The BankFactory Contract
Now, implement the factory that instantiates Bank contracts:
contract BankFactory {
Bank[] public list_of_banks;
function createBank(address _owner, uint256 _funds) external {
Bank newBank = new Bank(_owner, _funds);
list_of_banks.push(newBank);
}
}Key points:
new Bank(...)deploys a new instance on-chain.- The returned address is stored in
list_of_banks, allowing future interaction. - All state variables are set during construction and cannot be altered post-deployment.
Once deployed, calling createBank(owner, 100) generates a fresh contract with those parameters — no manual deployment needed.
Testing with HardHat: End-to-End Walkthrough
To verify functionality, we'll compile and test our contracts using HardHat, a popular Ethereum development environment.
1. Set Up Your Project
Initialize a new Node.js project and install HardHat:
npm install --save-dev hardhat
npx hardhatChoose "Create a JavaScript project" and follow prompts.
2. Add the Solidity Code
Create contracts/BankFactory.sol and paste both contracts inside.
3. Compile the Contracts
Run:
npx hardhat compileYou should see confirmation that both Bank and BankFactory compiled successfully.
4. Write a Test Script
Create test/bank-test.js with the following:
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("BankFactory and Bank Deployment", function () {
it("Should deploy banks and store correct data", async function () {
const BankFactory = await ethers.getContractFactory("BankFactory");
const bankFactory = await BankFactory.deploy();
await bankFactory.deployed();
const owner = "0x0d8D32B83aaBBB675333468E4794eE0cDE666666";
await bankFactory.createBank(owner, 69420);
await bankFactory.createBank(owner, 100);
await bankFactory.createBank(owner, 113377);
const bankAddresses = await bankFactory.list_of_banks();
const Bank = await ethers.getContractFactory("Bank");
const bank1 = Bank.attach(bankAddresses[0]);
const bank2 = Bank.attach(bankAddresses[1]);
const bank3 = Bank.attach(bankAddresses[2]);
expect(await bank1.owner()).to.equal(owner);
expect(await bank1.bank_funds()).to.equal(69420);
expect(await bank2.bank_funds()).to.equal(100);
expect(await bank3.bank_funds()).to.equal(113377);
console.log("All banks created successfully with correct state.");
});
});5. Run the Test
Execute:
npx hardhat testIf everything works, you’ll see a passing test and logs confirming each bank’s state.
👉 See how leading Web3 projects automate contract deployment at scale.
Frequently Asked Questions (FAQ)
Q: Can a factory track all deployed contracts?
A: Yes. By storing contract addresses in an array (like list_of_banks), the factory maintains full visibility and allows iteration or lookup later.
Q: Is there gas overhead when creating contracts dynamically?
A: Yes. Each new operation incurs higher gas due to bytecode deployment. Optimize by minimizing constructor logic and reusing libraries.
Q: Can deployed contracts be upgraded?
A: Not directly. Since each instance is immutable, consider using proxy patterns if upgradability is required.
Q: How do I interact with a newly created contract externally?
A: Use the contract ABI and its known address (from events or arrays) to connect via Ethers.js or Web3.js.
Q: Should I emit events when creating contracts?
A: Absolutely. Emitting an event like BankCreated(address owner, address bankAddress) improves transparency and indexability.
Q: Can anyone call the create function?
A: In our example, yes (external). Add access control (e.g., onlyOwner) if you want to restrict who can create contracts.
Keywords for SEO Optimization
Core keywords naturally integrated throughout this article include:
- Solidity contract factory
- create contract in Solidity
- deploy contract from contract
- dynamic contract instantiation
- HardHat testing
- smart contract design patterns
- Ethereum contract deployment
- new keyword Solidity
These terms align with common developer search queries related to advanced Solidity programming and dApp architecture.
Final Thoughts
Mastering contract factories unlocks scalable and modular smart contract architectures. From DeFi protocols to no-code platforms, this pattern empowers developers to build systems where users can generate customized logic without direct blockchain interaction.
By combining clean Solidity syntax with robust testing in HardHat, you ensure reliability and maintainability — critical for production-grade applications.
👉 Accelerate your smart contract development cycle with professional tools.