foundry-rs / foundry-rs/foundry

feat(cheatcode): add support for Vyper blueprint

Open
#11,530 1 comment 1 reaction 0 assignees View on GitHub
A-cheatcodes A-compiler C-forge T-feature T-to-discuss
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.