Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guide to using Ignition to deploy Diamonds (ERC-2535) #775

Open
kanej opened this issue Jun 4, 2024 · 3 comments
Open

Guide to using Ignition to deploy Diamonds (ERC-2535) #775

kanej opened this issue Jun 4, 2024 · 3 comments
Labels
status:ready This issue is ready to be worked on

Comments

@kanej
Copy link
Member

kanej commented Jun 4, 2024

First discussed on discord: https://discord.com/channels/750408878008827925/1153426756901032037/1247471045921734759

We should provide an example guide for deploying upgrade-able contracts based on the Diamond pattern ERC-2535.

@kanej kanej added status:triaging status:ready This issue is ready to be worked on and removed status:triaging labels Jun 4, 2024
@pash7ka
Copy link

pash7ka commented Jun 4, 2024

Right now I'm trying this approach:

import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
import { toFunctionSelector, zeroAddress } from "viem";

const FacetCutAction = {
    Add: 0,
    Replace: 1,
    Remove: 2,
};

export default buildModule("DiamondModule", (m) => {
    // Diamond Future
    const diamond = m.contract("Diamond");

    // Facet Futures
    const tokenAdminFacet = m.contract("TokenAdminFacet");
    const erc20Facet= m.contract("Erc20Facet");

    // Add facets to the diamond
    // TODO: take selectors from ABIs
    const tokenAdminFacetSelectors = [
        toFunctionSelector("function setMetadata(string calldata name, string calldata symbol)"),
        toFunctionSelector("function mint(address to, uint256 amount)"),
    ];

    const erc20FacetSelectors = [
        toFunctionSelector("function totalSupply()"),
        toFunctionSelector("function balanceOf(address account)"),
        toFunctionSelector("function allowance(address holder, address spender)"),
        toFunctionSelector("function approve(address spender, uint256 amount)"),
        toFunctionSelector("function transfer(address recipient, uint256 amount)"),
        toFunctionSelector("function transferFrom(address holder, address recipient, uint256 amount)"),
        toFunctionSelector("function name()"),
        toFunctionSelector("function symbol()"),
        toFunctionSelector("function decimals()"),
    ];
    
     const facetCutActions = [
        {
            action: FacetCutAction.Add,
            target: tokenFacetSelectors,
            selectors: tokenAdminFacetSelectors ,
        },
        {
            action: FacetCutAction.Add,
            target: erc20Facet,
            selectors: erc20FacetSelectors,
        },
    ];

    m.call(diamond, "diamondCut", [facetCutActions, zeroAddress, "0x"]);

    //TODO: return diamond combined with facets

    return { diamond };
});

In the test i have:

        const { diamond } = await hre.ignition.deploy(DiamondModule);
        diamond.write.setMetadata("My Token", "MTKN");

And here i have an error, that setMetadata does not exist. Obviously that's because diamond type doesn't know anything about facet ABIs.

@kanej
Copy link
Member Author

kanej commented Jun 5, 2024

I don't have experience with diamond deployments, but reading over the code, you have a deployment that sets the facets for the diamond contract and returns it. The hre.ignition.deploy(DiamondModule) returns a viem contract instance but the type information on the contract instance doesn't reflect the facets the diamond has been "cut" with.

Are you able to use viem to make an arbitrary call to the facet function on the deployed contract? Maybe using something like writeContract?

@pash7ka
Copy link

pash7ka commented Jun 5, 2024

Yes, i can do it in test like this:

        const tokenAdminFacetArtifact = await hre.artifacts.readArtifact("TokenAdminFacet");
        const erc20FacetArtifact = await hre.artifacts.readArtifact("Erc20Facet");

        const tokenAdminFacet= getContract({
            address: diamond.address,
            abi: tokenAdminFacetArtifact.abi,
            client: deployer
        });
        
        await tokenAdminFacet.write.setMetadata(["My Token", "MTKN"]);

This works. But i see it as a workaraund, not a perfect solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status:ready This issue is ready to be worked on
Projects
Status: Todo
Development

No branches or pull requests

2 participants