This project implements an upgradeable ERC20 token using the Diamond Standard (EIP-2535), allowing for modular and upgradeable smart contracts. contract address: 0x615D88af261c979532876A4f842b6321349BEfF4
The Diamond Standard (EIP-2535) enables a single contract to use multiple implementation contracts (facets) and allows upgrading functionality without changing the contract address. This implementation combines the Diamond pattern with ERC20 token functionality.
- Diamond.sol: The main proxy contract that delegates calls to facets
- DiamondCutFacet.sol: Manages adding, replacing, and removing facets
- DiamondLoupeFacet.sol: Provides introspection functions to query the diamond
- LibDiamond.sol: Library containing diamond storage and internal functions
- ERC20Facet.sol: ERC20 token implementation as a facet
project-root/
├── contracts/
│ ├── Diamond.sol
│ ├── facets/
│ │ ├── DiamondCutFacet.sol
│ │ ├── DiamondLoupeFacet.sol
│ │ └── ERC20Facet.sol
│ ├── interfaces/
│ │ ├── IDiamondCut.sol
│ │ └── IDiamondLoupe.sol
│ ├── libraries/
│ │ └── LibDiamond.sol
│ └── upgradeInitializers/
│ └── DiamondInit.sol
├── scripts/
│ ├── deploy.js
│ └── upgrade.js
├── test/
│ └── diamondTest.js
└── hardhat.config.js
- Node.js (v14+ recommended)
- npm or yarn
- Hardhat
- Clone the repository:
git clone <repository-url>
cd Diamond_contract- Install dependencies:
npm install- Create a
.envfile:
PRIVATE_KEY=your_private_key_here
INFURA_API_KEY=your_infura_key_here
ETHERSCAN_API_KEY=your_etherscan_key_hereEdit hardhat.config.js to configure networks:
networks: {
hardhat: {},
sepolia: {
url: `https://sepolia.infura.io/v3/${process.env.INFURA_API_KEY}`,
accounts: [process.env.PRIVATE_KEY]
}
}The deployment happens in stages:
npx hardhat run scripts/deploy.js --network <network-name>Deployment steps:
- Deploy DiamondCutFacet (upgrade facet)
- Deploy Diamond contract with DiamondCutFacet
- Deploy DiamondInit (initialization contract)
- Deploy additional facets (DiamondLoupeFacet, ERC20Facet)
- Execute diamondCut to add facets to the Diamond
npx hardhat verify --network <network-name> <contract-address>To add, replace, or remove functions:
npx hardhat run scripts/upgrade.js --network <network-name>The upgrade script:
- Deploys new facet contract
- Prepares diamondCut data (function selectors + facet address)
- Executes diamondCut transaction
Run the test suite:
npx hardhat testRun specific test file:
npx hardhat test test/diamondTest.jsRun with gas reporting:
REPORT_GAS=true npx hardhat testThe diamondCut function is used to add, replace, or remove functions:
enum FacetCutAction {Add, Replace, Remove}
struct FacetCut {
address facetAddress;
FacetCutAction action;
bytes4[] functionSelectors;
}Uses Diamond Storage pattern to avoid storage collisions between facets:
bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");Each function is identified by its 4-byte selector. The diamond routes calls based on these selectors to the appropriate facet.
| Command | Description |
|---|---|
npx hardhat compile |
Compile contracts |
npx hardhat test |
Run tests |
npx hardhat run scripts/deploy.js |
Deploy diamond |
npx hardhat run scripts/upgrade.js |
Upgrade diamond |
npx hardhat node |
Start local node |
npx hardhat clean |
Clear cache and artifacts |
After deployment, interact with the diamond using the combined ABI of all facets:
const diamond = await ethers.getContractAt('ERC20Facet', diamondAddress);
await diamond.transfer(recipientAddress, amount);- Unlimited Contract Size: Bypass 24KB contract size limit
- Upgradeable: Add, replace, or remove functions
- Single Address: Maintain same address through upgrades
- Modular: Organize code into logical facets
- Gas Efficient: Share code between contracts
- Always audit facets before deployment
- Implement proper access controls on diamondCut
- Test upgrades on testnet first
- Consider using a timelock for upgrades
- Use multi-sig for ownership
MIT
Diamond: 0x615D88af261c979532876A4f842b6321349BEfF4 DiamondCutFacet: 0xcd018d90BAB1030F2Cf0E8F90E555C296CedA263 DiamondInit: 0x9De7547161ea6dC55770525B760E2f57E545305B