首先,我们先了解一下promptcheatcode

prompt

Signature

function prompt(string calldata promptText) external returns (string memory input);
function promptSecret(string calldata promptText) external returns (string memory input);
function promptSecretUint(string calldata promptText) external returns (uint256);

Description

向用户显示插入任意数据的交互式提示。

vm.prompt显示一个交互式输入,而vm.promptSecretvm.promptSecretUint显示一个隐藏的输入,用于密码和其他不应泄漏到中断的秘密信息。

Note:

此 cheatcode 旨在用于脚本,而并非测试。

对于该 cheatcode,为了防止不必要的挂断,vm.prompt有一个超时配置:

在 Foundry.toml 中:

prompt_timeout = 120

默认值为 120,单位为秒

一个简单的例子

对于 Foundry init 后附带的三个默认合约,我们对Counter.s.sol进行如下的修改:

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

import {Script, console} from "forge-std/Script.sol";
import {Counter} from "../src/Counter.sol";

contract CounterScript is Script {
    Counter public counter;

    function setUp() public {}

    function run() public {
        vm.startBroadcast();

        counter = new Counter();
        uint256 number = vm.parseUint(vm.prompt("Set Number: ")); 
        counter.setNumber(number);
        vm.stopBroadcast();
    }
}

其中:parseUintcheatcode 的作用是将prompt从命令行捕获的数据转换为 uint256类型

我们运行一下:

img

可以看到,Foundry 为我们给出了一个交互的输入。我们在这里传入我们要设置的 number 即可。

image-20241102120413965

使用这个 cheatcode,大大方便了我们在后续过程中多次修改 script 的问题。

不过有一点需要注意:该 cheatcode 在非交互式 shell 中运行时回滚。

这就引出了一个问题:如果我们按照这个例子的方式书写我们的 script 的话,我们这个脚本将无法在后续的 test 中集成。所以,这就可以展示我们的最佳实践了。

最佳实践

在 test 中集成包含vm.prompt的脚本时,可以使用这样的模式:

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

import {Script, console} from "forge-std/Script.sol";
import {Counter} from "../src/Counter.sol";

contract CounterScript is Script {
    Counter public counter;

    function setUp() public {}

    function run() public {
        uint256 number = vm.parseUint(vm.prompt("Number: "));
        run(number);
    }

    function run(uint256 myUint) public {
        vm.startBroadcast();

        counter = new Counter();
        counter.setNumber(myUint);

        vm.stopBroadcast();
    }
}

这样,我们直接运行该脚本时,他会为我们提供可交互的环境来获取数据;当我们想要将其集成到 test 时,直接调用 run(uint256)这个函数签名的 run函数就可以了。