Deploy Precompiled NPM Smart Contract Artifacts with Hardhat & ethers.js
This guide explains why compiling third‑party contracts from node_modules fails and shows a robust method to deploy precompiled artifacts directly using Hardhat and ethers.js, with step‑by‑step code examples for UniswapV3Factory.
Why Direct Compilation Fails
When developers try to compile contracts from npm packages such as @uniswap/v3-core, they encounter a "wall" because the published packages contain only interface definitions and precompiled artifact files (ABI and bytecode), not the original .sol source files. Consequently, ethers.getContractFactory("ContractName") cannot locate bytecode, and importing the source leads to dependency errors.
Solution: Use Precompiled Artifacts Directly
The recommended approach is to bypass Hardhat’s compilation step and import the ready‑made artifact JSON files from node_modules. These artifacts provide everything needed for deployment: the contract’s ABI and bytecode.
Step 1 – Locate the Artifact
Find the JSON file inside the package. For Uniswap V3 core the path is:
@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.jsonStep 2 – Import the Artifact
In the deployment script, import the file just like a regular Node module:
// scripts/deploy-uniswap.js
const UniswapV3FactoryArtifact = require("@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json");The UniswapV3FactoryArtifact object now contains abi and bytecode.
Step 3 – Create a ContractFactory with ethers.js
Use the ethers.js ContractFactory constructor to build a factory from the extracted ABI and bytecode:
const { ethers } = require("hardhat");
async function main() {
const [deployer] = await ethers.getSigners();
const factoryAbi = UniswapV3FactoryArtifact.abi;
const factoryBytecode = UniswapV3FactoryArtifact.bytecode;
const Factory = new ethers.ContractFactory(factoryAbi, factoryBytecode, deployer);
console.log("Deploying UniswapV3Factory...");
const factory = await Factory.deploy();
console.log("Waiting for deployment confirmation...");
await factory.waitForDeployment();
console.log("✅ UniswapV3Factory deployed to:", factory.target);
}
main().then(() => process.exit(0)).catch(error => { console.error("❌ Deployment failed:", error); process.exit(1); });Note that with ethers.js v6 the old .deployed() method is deprecated; use waitForDeployment() and factory.target to obtain the address.
Full Script Example
// scripts/deploy-uniswap.js
const { ethers } = require("hardhat");
const UniswapV3FactoryArtifact = require("@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json");
async function main() {
console.log("Fetching deployer account...");
const [deployer] = await ethers.getSigners();
console.log("Deploying with account:", deployer.address);
const factoryAbi = UniswapV3FactoryArtifact.abi;
const factoryBytecode = UniswapV3FactoryArtifact.bytecode;
console.log("Creating ContractFactory from ABI & bytecode...");
const Factory = new ethers.ContractFactory(factoryAbi, factoryBytecode, deployer);
console.log("Deploying UniswapV3Factory...");
const factory = await Factory.deploy();
console.log("Waiting for contract deployment...");
await factory.waitForDeployment();
console.log("✅ UniswapV3Factory successfully deployed to:", factory.target);
}
main().then(() => process.exit(0)).catch(error => { console.error("❌ Deployment failed:", error); process.exit(1); });Benefits of This Approach
Robust and Reliable – Uses the officially published bytecode that has been thoroughly tested, avoiding compiler version or optimizer mismatches.
Simple and Efficient – No need for proxy contracts, custom path mappings, or additional Hardhat configuration; the deployment logic stays in the script.
Highly Portable – Works for any third‑party protocol that distributes precompiled artifacts via npm, making it a universal pattern for external dependencies.
By mastering direct artifact deployment, developers can streamline their Hardhat workflow and confidently integrate core DeFi protocols into local testing environments.
Ops Development & AI Practice
DevSecOps engineer sharing experiences and insights on AI, Web3, and Claude code development. Aims to help solve technical challenges, improve development efficiency, and grow through community interaction. Feel free to comment and discuss.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
