#部署 #forge #keep #set #track #name #contract

app forge-deploy

一个与一系列Solidity合约协同使用的cli,用于在Forge中通过名称跟踪部署

39次发布

0.2.0 2023年5月19日
0.1.0 2023年5月12日
0.0.37 2023年5月12日
0.0.27 2023年4月29日

#10 in #forge

Download history 24/week @ 2024-03-12 40/week @ 2024-03-26 198/week @ 2024-04-02

354 每月下载量

MIT 许可证

89KB
1.5K SLoC

Rust 854 SLoC // 0.1% comments Solidity 360 SLoC // 0.3% comments JavaScript 202 SLoC // 0.2% comments Handlebars 40 SLoC

forge-deploy

一个cli和相关合约,用于通过名称跟踪部署并在Solidity中重用。

它尽可能与hardhat-deploy保持兼容(工作进行中)。

forge-deploy旨在提供最小化功能集,为Foundry提供一个优雅的部署系统。

入门模板

https://github.com/wighawag/template-foundry

功能

  • 为Forge合约生成类型安全的部署函数。无需传递文本字符串并希望abi编码的参数顺序正确或类型正确。
  • 将部署保存到json文件(基于hardhat-deploy模式)
  • 基于模板和Solidity库的模块化系统

模块化

该系统是模块化的。默认提供的部署函数提供了一组基本功能,但系统可以通过自定义函数轻松扩展。请参阅contracts/DefaultDeployerFunction.sol以及如何将其作为一个简单的库自行提供。forge-deploy真正提供的是contrats/Deployer.sol中特定的函数集来saveget部署

如何使用

有两种入门方式,一种是不使用npm,另一种是使用npm

使用npm

  1. 有一个带有npm的forge项目,并进入它

    mkdir my-project;
    cd my-project;
    forge init;
    npm init
    
  2. 添加forge-deploy包

    npm i -D forge-deploy
    

    这将自动安装forge-deploy二进制文件

  3. 将生成的文件添加到.gitignore中

    cat >> .gitignore <<EOF
    
    # forge-deploy
    /generated
    /deployments/localhost
    /deployments/31337
    EOF
    
  4. 您还需要通过编辑foundry.toml允许forge在特定路径上读取和写入

    cat >> foundry.toml <<EOF
    
    fs_permissions = [
    	{ access = "read", path = "./deployments"},
    	{ access = "read", path = "./out"},
    ]
    EOF
    
  5. 生成类型安全的部署函数

    在package.json中添加一些脚本

    {
      "scripts": {
        "compile": "forge-deploy gen-deployer && forge build",
        "deploy": "forge script script/Counter.s.sol --rpc-url $RPC_URL --broadcast --private-key $DEPLOYER_PRIVATE_KEY -v && forge-deploy sync;"
      }
    }
    

    注意我们如何在脚本执行后直接执行forge-deploy sync。这样,forge-deploy将跟踪新的部署。

  6. 添加部署脚本

    添加文件 script/Deploy.s.sol 并包含以下内容

    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.13;
    
    import "forge-deploy/DeployScript.sol";
    import "generated/deployer/DeployerFunctions.g.sol";
    
    contract Deployments is DeployScript {
    	using DeployerFunctions for Deployer;
    
    	function deploy() external returns (Counter) {
    		return deployer.deploy_Counter("MyCounter");
    	}
    }
    

    将调用 deploy 函数,由于脚本扩展了 DeployScript(它本身扩展了来自 forge-std 的 Script),因此您将能够访问 deployer 变量。

    此变量主要公开了 save 和 get 函数。部署功能实际上在像这里提供的 "DeployerFunctions.g.sol" 这样的库中实现,这是从上面的命令生成的代码: forge-deploy gen-deployer;

  7. 现在可以通过 forge 脚本来执行脚本

    npm run deploy
    

    注意,在使用 anvil(本地网络)时,您需要为 forge-deploy 设置 DEPLOYMENT_CONTEXT 环境变量以保存部署

       DEPLOYMENT_CONTEXT=localhost npm run deploy
    

    这对于使用默认 chain id 31337 的 localhost 是必要的,因为 forge-deploy 默认不会在该 chainId 上保存部署(同样适用于 1337)。这样它就不会与使用 chainId=31337 的内存测试发生冲突

    DEPLOYMENT_CONTEXT 环境变量还允许您在同一个网络上隔离不同的部署上下文。如果没有指定,上下文是 chainId

无需 npm

  1. 拥有一个 forge 项目,并进入其中

    mkdir my-project;
    cd my-project;
    forge init;
    
  2. 添加forge-deploy包

    forge install wighawag/[email protected];
    
  3. 直接从 lib/forge-deploy 构建 cli

    cd lib/forge-deploy;
    cargo build --release;
    cp target/release/forge-deploy ../../forge-deploy;
    

    在上面的最后一步中,我们还将其复制到项目文件夹中,以便于访问

    这样,您就可以通过以下方式执行它

    ./forge-deploy <command>
    

    如果您不想使用 cargo,也可以下载二进制文件: https://github.com/wighawag/forge-deploy/releases

  4. 在 .gitignore 中添加生成的文件和刚刚安装的二进制文件

    cat >> .gitignore <<EOF
    
    # forge-deploy
    /generated
    /deployments/localhost
    /deployments/31337
    
    # forge-deploy cli binary
    /forge-deploy
    EOF
    
  5. 您还需要通过编辑foundry.toml允许forge在特定路径上读取和写入

    cat >> foundry.toml <<EOF
    
    fs_permissions = [
    	{ access = "read", path = "./deployments"},
    	{ access = "read", path = "./out"}
    ]
    EOF
    
  6. 生成类型安全的部署函数

    ./forge-deploy gen-deployer;
    
  7. 添加部署脚本

    添加文件 script/Deploy.s.sol 并包含以下内容

    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.13;
    
    import "forge-deploy/DeployScript.sol";
    import "generated/deployer/DeployerFunctions.g.sol";
    
    contract Deployments is DeployScript {
    	using DeployerFunctions for Deployer;
    
    	function deploy() external returns (Counter) {
    		return deployer.deploy_Counter("MyCounter");
    	}
    }
    

    将调用 deploy 函数,由于脚本扩展了 DeployScript(它本身扩展了来自 forge-std 的 Script),因此您将能够访问 deployer 变量。

    此变量主要公开 save 和 get 函数。部署功能实际上在像这里提供的 "DeployerFunctions.g.sol" 这样的库中实现,这是从上面的命令生成的代码: ./forge-deploy gen-deployer;

  8. 现在可以通过 forge 脚本来执行脚本

    请注意,您需要直接执行 ./forge-deploy sync

    例如

    forge script script/Counter.s.sol --rpc-url $RPC_URL --broadcast --private-key $DEPLOYER_PRIVATE_KEY -v && ./forge-deploy sync;
    

    使用 anvil 和默认账户

    DEPLOYMENT_CONTEXT=localhost forge script script/Counter.s.sol --rpc-url http://127.0.0.1:8545 --broadcast --private-key ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 -v && ./forge-deploy sync;
    

    请注意,这里我们指定了 DEPLOYMENT_CONTEXT 环境变量。这对于使用默认 chain id 31337 的 localhost 是必要的,因为 forge-deploy 默认不会在该 chainId 上保存部署(同样适用于 1337)。这样它就不会与使用 chainId=31337 的内存测试发生冲突

    DEPLOYMENT_CONTEXT 环境变量还允许您在同一个网络上隔离不同的部署上下文。如果没有指定,上下文是 chainId

快速开始

在某个地方启动 anvil

anvil;

然后复制并执行此操作,查看结果

mkdir my-forge-deploy-project;
cd my-forge-deploy-project;
forge init;
forge install wighawag/[email protected];
cd lib/forge-deploy;
cargo build --release;
cp target/release/forge-deploy ../../forge-deploy;
cd ../..;
cat >> foundry.toml <<EOF

fs_permissions = [
	{ access = "read", path = "./deployments"},
	{ access = "read", path = "./out"}
]
EOF
cat >> .gitignore <<EOF

# forge-deploy
/generated
/deployments/localhost
/deployments/31337

EOF
./forge-deploy gen-deployer;
cat > script/Deploy.s.sol <<EOF
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-deploy/DeployScript.sol";
import "generated/deployer/DeployerFunctions.g.sol";

contract Deployments is DeployScript {
	using DeployerFunctions for Deployer;

	function deploy() external returns (Counter) {
		return deployer.deploy_Counter("MyCounter");
	}
}
EOF
DEPLOYMENT_CONTEXT=localhost forge script script/Deploy.s.sol --rpc-url http://127.0.0.1:8545 --broadcast --private-key ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 -v && ./forge-deploy sync;

在测试中可重用

forge 脚本的一个非常棒的特性,仍然保留在 forge-deploy 中,就是能够在测试中使用脚本。

这允许您在测试中重复使用部署过程!

例如,这里是对 Counter 的基本测试。将以下内容复制到现有的 test/Counter.t.sol 中,并运行测试以查看其效果

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "../src/Counter.sol";
import "../script/Deploy.s.sol";
contract CounterTest is Test {
	Counter public counter;
	function setUp() public {
		counter = new Deployments().deploy();
		counter.setNumber(0);
	}
	function testIncrement() public {
		counter.increment();
		assertEq(counter.number(), 1);
	}
	function testSetNumber(uint256 x) public {
		counter.setNumber(x);
		assertEq(counter.number(), x);
	}
}

像往常一样,要运行测试,您可以执行以下操作

forge test

更多信息

请注意,生成的 Solidity 是可选的。

您也可以简单地使用默认的 deploy 函数

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-deploy/DeployScript.sol";
import "forge-deploy/DefaultDeployerFunction.sol";
import "../src/Counter.sol";

contract Deployments is DeployScript {
	using DefaultDeployerFunction for Deployer;

	function deploy() external returns (Counter) {
		return Counter(
			deployer.deploy(
				"MyCounter",
				"Counter.sol:Counter", // forge's artifact id
				"" // no arguments: empty bytes
			)
		);
	}
}

依赖关系

~6–15MB
~194K SLoC