scaffold-eth / scaffold-eth-2

Open source forkable Ethereum dev stack
https://scaffoldeth.io
MIT License
1.41k stars 887 forks source link

foundry: separate out your contract deployments #898

Closed technophile-04 closed 3 months ago

technophile-04 commented 4 months ago

Description:

Separate your contract deploy script from so that we enforce people to follow a pattern.

The reason we need to enforce this pattern is because exportDeployments() should be called only once and too after all the deployments are done.

So basically Deploy.s.sol file is the main file which import different deploy script of different contracts and in the end it calls the exportDeployments() which creates all the necessary files for generateTsAbi.js fucntion.

Checkout second part of this for more details : https://github.com/scaffold-eth/scaffold-eth-2/pull/781#issuecomment-2018642266

CC @jrcarlos2000 feel free suggest some cleanups / better practices in foundry.

Some notes:

jrcarlos2000 commented 3 months ago
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { YourContract } from "../contracts/YourContract.sol";
import { ScaffoldETHDeploy, console } from "./DeployHelpers.s.sol";

contract DeployScript is ScaffoldETHDeploy {
  error InvalidPrivateKey(string);

  modifier deploymentExporter() {
    _;
    exportDeployments();
  }

  function run() external deploymentExporter {
    address deployer = _startBroadcast();
    YourContract yourContract = new YourContract(deployer);
    console.logString(
      string.concat(
        "YourContract deployed at: ", vm.toString(address(yourContract))
      )
    );
    _stopBroadcast();
  }

  function test() public { }
}

we can avoid having users explicitly calling exportDeployments() by using this modifier which will execute after function run()

jrcarlos2000 commented 3 months ago

another way could be having abstract contract for each deploy script. we can share the deployments array for named contracts, for example when deploying multiple instances of a same contract so that we can export all of them with different names. This is currently available and is useful, hardhat used to have a similar functionality.

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "../contracts/YourContract.sol";
import "./DeployHelpers.s.sol";

abstract contract DeployYourContract is ScaffoldETHDeploy {
  function run() public virtual {
    uint256 deployerPrivateKey = setupLocalhostEnv();
    vm.startBroadcast(deployerPrivateKey);

    YourContract yourContract = new YourContract(vm.addr(deployerPrivateKey));
    deployments.push(Deployment("YourContract0", address(yourContract)));
    console.logString(
      string.concat(
        "YourContract deployed at: ", vm.toString(address(yourContract))
      )
    );

    vm.stopBroadcast();
  }
}

import "../contracts/YourContract.sol"; import "./DeployHelpers.s.sol";

abstract contract DeployYourContract1 is ScaffoldETHDeploy { function run() public virtual{ uint256 deployerPrivateKey = setupLocalhostEnv(); vm.startBroadcast(deployerPrivateKey);

YourContract yourContract = new YourContract(vm.addr(deployerPrivateKey));
deployments.push(Deployment("YourContract1", address(yourContract)));
console.logString(
  string.concat(
    "YourContract deployed at: ", vm.toString(address(yourContract))
  )
);

vm.stopBroadcast();

} }


- main deploy script 

```solidity
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { DeployYourContract } from "./00_deploy_your_contract.s.sol";
import { DeployYourContract1 } from "./01_deploy_your_contract.s.sol";

contract DeployScript is DeployYourContract, DeployYourContract1 {
  uint256 deployerPrivateKey;

  error InvalidPrivateKey(string);

  modifier scaffoldEthDeployer() {
    deployerPrivateKey = setupLocalhostEnv();
    if (deployerPrivateKey == 0) {
      revert InvalidPrivateKey(
        "You don't have a deployer account. Make sure you have set DEPLOYER_PRIVATE_KEY in .env or use `yarn generate` to generate a new random account"
      );
    }
    _;
    exportDeployments();
  }

  function run()
    public
    override(DeployYourContract, DeployYourContract1)
    scaffoldEthDeployer
  {
    DeployYourContract.run();
    DeployYourContract1.run();
  }
}
jrcarlos2000 commented 3 months ago

another way could be having abstract contract for each deploy script. we can share the deployments array for named contracts, for example when deploying multiple instances of a same contract so that we can export all of them with different names. This is currently available and is useful, hardhat used to have a similar functionality.

The current approach doesnt support this shared state of deployments for named contracts @technophile-04

technophile-04 commented 3 months ago

Ohh I see, so with current approach people are not able to same contract(name) multiple times it gets override by most recent one?

I think we kind of the same problem with current setup of hardhat-deploy(where you are not able to keep track of contract with same names)

Yeah your approach makes sense! The only thing which I don't like is people in their own contract deploy script has to remember to do :

deployments.push(Deployment("YourContract1", address(yourContract)));

but yeah I am not sure what's other way to handle this either, something not that important for now but we should def tackle this in future! Thanks @jrcarlos2000 for all the suggestions!!