foundry-rs / foundry-rs/foundry
feat(cheatcode): add support for Vyper blueprint
- Dominant language
- Rust
- Stars
- 10.6k
- Forks
- 2.6k
- Avg merge
- 18h 20m
- Merged PRs (30d)
- 510
Description
### Component
Forge
### Describe the feature you would like
Currently, the `vm.deployCode` cheatcode works perfectly for deploying standard Vyper contracts. However, it reverts when attempting to deploy a Vyper contract that is meant to be a **blueprint** (one that would be deployed using [`create_from_blueprint `](https://docs.vyperlang.org/en/stable/built-in-functions.html#create_from_blueprint)).
The ideal solution would be a native, straightforward cheatcode to deploy Vyper blueprint contracts. This could be implemented in one of two ways:
1. **Extend `deployCode`:** Enhance the existing `deployCode` (and `deployCodeTo`) cheatcode to accept additional args and correctly handle Vyper blueprint source files.
2. **Add a new cheatcode:** Introduce a dedicated cheatcode, such as `deployBlueprint(string memory path)` or `deployBlueprintCode(string memory code)`, specifically for this purpose.
Either approach would be a significant improvement over the current state.
I have a working solution that uses `vm.ffi` to call the `vyper` compiler with the correct flags and then deploys the resulting bytecode using inline assembly.
While this workaround is functional, it's not ideal because it requires the `--ffi` flag and involves manual, low-level assembly, which is less accessible and more error-prone than a dedicated cheatcode.
```solidity
/// @notice Deploys a Vyper blueprint contract using ffi to compile and assembly to create.
/// @param path The path to the Vyper source file.
/// @param label A label for the deployed blueprint address in traces.
/// @return blueprint The address of the deployed blueprint contract.
function deployBlueprint(
string memory path,
string memory label
) internal returns (address blueprint) {
// Prepare the command to compile the contract to blueprint bytecode
string[] memory inputs = new string[](4);
inputs[0] = "vyper";
inputs[1] = "-f";
inputs[2] = "blueprint_bytecode";
inputs[3] = path;
// Execute the command via FFI to get the deployment code
bytes memory bytecode = vm.ffi(inputs);
// Deploy the bytecode using the CREATE opcode
assembly {
// create(value, offset, length)
blueprint := create(0, add(bytecode, 0x20), mload(bytecode))
}
require(blueprint != address(0), "deployBlueprint: Deployment failed");
vm.label(blueprint, string.concat(label, " Blueprint"));
}
```
Example usage:
```solidity
// Deploy the Twocrypto.vy contract as a blueprint
address twocryptoBlueprint = deployBlueprint(
"contracts/testing/twocrypto/Twocrypto.vy",
"Twocrypto"
);
```
### Additional context
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.