The Musixverse Diamond is an implementation that leverages the EIP-2535 Diamond Standard.
The standard loupe functions have been gas-optimized in this implementation and can be called in on-chain transactions.
Note: The loupe functions in DiamondLoupeFacet.sol MUST be added to the diamond and are required by the EIP-2535 Diamonds standard.
- Clone this repo:
git clone https://github.com/Musixverse/musixverse-diamond.git
- Install NPM packages:
cd musixverse-diamond
npm install
To run all test files-
npx hardhat test
To run a single test file-
npx hardhat test test/musixverse.test.js
npx hardhat size-contracts
Create a .env
file in the .env.example
file format.
Add your secrets and api keys.
npx hardhat run scripts/deploy.js
or
npx hardhat deploy --network <NETWORK_NAME>
New contract addresses will automatically be added to the contract_addresses.js
file.
Things to keep in mind during development & deployment-
- Storage Collision
https://forum.openzeppelin.com/t/openzeppelin-upgrades-step-by-step-tutorial-for-hardhat/3580/4
- Constructor functions don't work in Facets
https://eip2535diamonds.substack.com/p/constructor-functions-dont-work-in?s=w
- DiamondCutFacet is deployed.
- The diamond is deployed, passing as arguments to the diamond constructor the owner address of the diamond and the DiamondCutFacet address. DiamondCutFacet has the
diamondCut
external function which is used to upgrade the diamond to add more functions. - The
DiamondInit
contract is deployed. This contains aninit
function which is called on the first diamond upgrade to initialize state of some state variables. Information on how thediamondCut
function works is here: https://eips.ethereum.org/EIPS/eip-2535#diamond-interface - Facets are deployed.
- The diamond is upgraded. The
diamondCut
function is used to add functions from facets to the diamond. In addition thediamondCut
function calls theinit
function from theDiamondInit
contract usingdelegatecall
to initialize state variables.
Check that contract_addresses.js
has the correct facet addresses.
Then, run the script to verify all contracts at once-
npx hardhat verify-contracts --network mumbai
or
To verify contracts individually-
npx hardhat verify CONTRACT_ADDR --network mumbai
With constructor arguments-
npx hardhat verify 0x434c83d0d44eF9B6a2295C0a43DA2b065265075a --network mumbai "0x159507b2b3829791fAB794581D2aC074F3596013" "0x241AF116CBa2C7C8FBB461555Af19561Cd2904b7"
npx hardhat verify 0x42f6ac17A241fD6F27eb4d6BffE5f71FFeE04b9b --network mumbai "https://gateway.musixverse.com/ipfs/" "https://www.musixverse.com/contract-metadata-uri"
Check the scripts/upgrades/upgrade-MusixverseFacet.js
file for example of upgrades.
Note that any number of functions from any number of facets can be added/replaced/removed on a diamond in a single transaction. In addition an initialization function can be executed in the same transaction as an upgrade to initialize any state variables required for an upgrade. This 'everything done in a single transaction' capability ensures a diamond maintains a correct and consistent state during upgrades.
Refer- https://github.com/mudgen/diamond-3-hardhat/blob/main/test/diamondTest.js
- Check the task in
hardhat.config.js
& the upgrade file, and then run-
npx hardhat upgradeMusixverseFacet --network mumbai
-
Update the upgraded facet address in
contract_addresses.js
-
Then verify the contract-
npx hardhat verify CONTRACT_ADDR --network mumbai "https://gateway.musixverse.com/ipfs/" "https://www.musixverse.com/contract-metadata-uri"
The contracts/shared/MusixverseDiamond.sol
file shows the implementation of Musixverse Diamond.
The contracts/shared/facets/DiamondCutFacet.sol
file shows how to implement the diamondCut
external function.
The contracts/shared/facets/DiamondLoupeFacet.sol
file shows how to implement the four standard loupe functions.
The contracts/shared/libraries/LibDiamond.sol
file shows how to implement Diamond Storage and the diamondCut
internal function.
The scripts/deploy.js
file has functions that show how to deploy the diamond.
The test/diamond.test.js
file gives tests for the diamondCut
function and the Diamond Loupe functions.
- Start a local node
npx hardhat node
- Open a new terminal and deploy the smart contract on the localhost network
npx hardhat run --network localhost scripts/deploy_upgradeable_mxv.js
- As general rule, you can target any network configured in the hardhat.config.js
npx hardhat run --network <your-network> scripts/deploy_upgradeable_mxv.js
- For upgrading
npx hardhat run --network localhost scripts/upgrade_mxv_to_v2.js
npx hardhat console --network localhost
const Musixverse = await ethers.getContractFactory('MusixverseV1');
const mxv = await Musixverse.attach('0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9');
(await mxv.getMusixverseMain()).toString();
await mxv.setMusixverseMain("0x159507b2b3829791fAB794581D2aC074F3596013");
mxv.mintTrackNFT(1, 10, ["QmQQqbwJqzQqwfnjtsP1FwZQcYKroBiA5ppcEBc1fvPSTt"], ['0x159507b2b3829791fAB794581D2aC074F3596013'], [100], 5, true);