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 installTo run all test files-
npx hardhat testTo run a single test file-
npx hardhat test test/musixverse.test.jsnpx hardhat size-contractsCreate a .env file in the .env.example file format.
Add your secrets and api keys.
npx hardhat run scripts/deploy.jsor
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
diamondCutexternal function which is used to upgrade the diamond to add more functions. - The
DiamondInitcontract is deployed. This contains aninitfunction which is called on the first diamond upgrade to initialize state of some state variables. Information on how thediamondCutfunction works is here: https://eips.ethereum.org/EIPS/eip-2535#diamond-interface - Facets are deployed.
- The diamond is upgraded. The
diamondCutfunction is used to add functions from facets to the diamond. In addition thediamondCutfunction calls theinitfunction from theDiamondInitcontract usingdelegatecallto 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 mumbaior
To verify contracts individually-
npx hardhat verify CONTRACT_ADDR --network mumbaiWith 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);