Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change to a library and support sending a value during the deployment #9

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Now you are all set up and ready to go! Below is a quick example of how to set u

# Compiling/Testing Vyper Contracts

The VyperDeployer is a pre-built contract that takes a filename and deploys the corresponding Vyper contract, returning the address that the bytecode was deployed to. If you want, you can check out [how the VyperDeployer works under the hood](https://github.com/0xKitsune/Foundry-Vyper/blob/main/lib/utils/VyperDeployer.sol). Below is a quick example of how to setup and deploy a SimpleStore contract written in Vyper.
The VyperDeployer is a library that takes a filename and deploys the corresponding Vyper contract, returning the address that the bytecode was deployed to. If you want, you can check out [how the VyperDeployer works under the hood](https://github.com/0xKitsune/Foundry-Vyper/blob/main/lib/utils/VyperDeployer.sol). Below is a quick example of how to setup and deploy a SimpleStore contract written in Vyper.


## SimpleStore.Vyper
Expand Down
82 changes: 74 additions & 8 deletions lib/utils/VyperDeployer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ interface _CheatCodes {
function ffi(string[] calldata) external returns (bytes memory);
}

contract VyperDeployer {
library VyperDeployer {
address constant HEVM_ADDRESS =
address(bytes20(uint160(uint256(keccak256("hevm cheat code")))));

/// @notice Initializes cheat codes in order to use ffi to compile Vyper contracts
_CheatCodes cheatCodes = _CheatCodes(HEVM_ADDRESS);
_CheatCodes constant cheatCodes = _CheatCodes(HEVM_ADDRESS);

///@notice Compiles a Vyper contract and returns the address that the contract was deployeod to
///@notice Compiles a Vyper contract and returns the address that the contract was deployed to
///@notice If deployment fails, an error will be thrown
///@param fileName - The file name of the Vyper contract. For example, the file name for "SimpleStore.vy" is "SimpleStore"
///@return deployedAddress - The address that the contract was deployed to

function deployContract(string memory fileName) public returns (address) {
function deployContract(string memory fileName) internal returns (address) {
///@notice create a list of strings with the commands necessary to compile Vyper contracts
string[] memory cmds = new string[](2);
cmds[0] = "vyper";
Expand All @@ -43,12 +43,43 @@ contract VyperDeployer {
return deployedAddress;
}

///@notice Compiles a Vyper contract with constructor arguments and returns the address that the contract was deployeod to
///@notice Compiles a Vyper contract, sends a value during the deployment and returns the address that the contract was deployed to
///@notice If deployment fails, an error will be thrown
///@param fileName - The file name of the Vyper contract. For example, the file name for "SimpleStore.vy" is "SimpleStore"
///@param value - The amount of wei to send with the deployment
///@return deployedAddress - The address that the contract was deployed to
function deployContract(string memory fileName, bytes calldata args)
public

function deployContract(string memory fileName, uint256 value) internal returns (address) {
///@notice create a list of strings with the commands necessary to compile Vyper contracts
string[] memory cmds = new string[](2);
cmds[0] = "vyper";
cmds[1] = string.concat("vyper_contracts/", fileName, ".vy");

///@notice compile the Vyper contract and return the bytecode
bytes memory bytecode = cheatCodes.ffi(cmds);

///@notice deploy the bytecode with the create instruction
address deployedAddress;
assembly {
deployedAddress := create(value, add(bytecode, 0x20), mload(bytecode))
}

///@notice check that the deployment was successful
require(
deployedAddress != address(0),
"VyperDeployer could not deploy contract"
);

///@notice return the address that the contract was deployed to
return deployedAddress;
}

///@notice Compiles a Vyper contract with constructor arguments and returns the address that the contract was deployed to
///@notice If deployment fails, an error will be thrown
///@param fileName - The file name of the Vyper contract. For example, the file name for "SimpleStore.vy" is "SimpleStore"
///@return deployedAddress - The address that the contract was deployed to
function deployContract(string memory fileName, bytes memory args)
internal
returns (address)
{
///@notice create a list of strings with the commands necessary to compile Vyper contracts
Expand Down Expand Up @@ -78,9 +109,44 @@ contract VyperDeployer {
return deployedAddress;
}

///@notice Compiles a Vyper contract with constructor arguments, sends a value during the deployment and returns the address that the contract was deployed to
///@notice If deployment fails, an error will be thrown
///@param fileName - The file name of the Vyper contract. For example, the file name for "SimpleStore.vy" is "SimpleStore"
///@return deployedAddress - The address that the contract was deployed to
function deployContract(string memory fileName, bytes memory args, uint256 value)
internal
returns (address)
{
///@notice create a list of strings with the commands necessary to compile Vyper contracts
string[] memory cmds = new string[](2);
cmds[0] = "vyper";
cmds[1] = string.concat("vyper_contracts/", fileName, ".vy");

///@notice compile the Vyper contract and return the bytecode
bytes memory _bytecode = cheatCodes.ffi(cmds);

//add args to the deployment bytecode
bytes memory bytecode = abi.encodePacked(_bytecode, args);

///@notice deploy the bytecode with the create instruction
address deployedAddress;
assembly {
deployedAddress := create(value, add(bytecode, 0x20), mload(bytecode))
}

///@notice check that the deployment was successful
require(
deployedAddress != address(0),
"VyperDeployer could not deploy contract"
);

///@notice return the address that the contract was deployed to
return deployedAddress;
}

/// @dev Consider listening to the Blueprint if you haven't already
/// @param fileName - The file name of the Blueprint Contract
function deployBlueprint(string memory fileName) public returns (address) {
function deployBlueprint(string memory fileName) internal returns (address) {
///@notice create a list of strings with the commands necessary to compile Vyper contracts
string[] memory cmds = new string[](2);
cmds[0] = "vyper";
Expand Down
18 changes: 13 additions & 5 deletions src/test/SimpleStore.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,21 @@ import "../../lib/utils/VyperDeployer.sol";
import "../ISimpleStore.sol";

contract SimpleStoreTest is DSTest {
///@notice create a new instance of VyperDeployer
VyperDeployer vyperDeployer = new VyperDeployer();

ISimpleStore simpleStore;
ISimpleStore simpleStorePayable;
ISimpleStore simpleStoreBlueprint;
ISimpleStoreFactory simpleStoreFactory;

function setUp() public {
///@notice deploy a new instance of ISimplestore by passing in the address of the deployed Vyper contract
simpleStore = ISimpleStore(vyperDeployer.deployContract("SimpleStore", abi.encode(1234)));
simpleStore = ISimpleStore(VyperDeployer.deployContract("SimpleStore", abi.encode(1234)));

simpleStoreBlueprint = ISimpleStore(vyperDeployer.deployBlueprint("ExampleBlueprint"));
simpleStorePayable = ISimpleStore(VyperDeployer.deployContract("SimpleStorePayable", 4321));

simpleStoreFactory = ISimpleStoreFactory(vyperDeployer.deployContract("SimpleStoreFactory"));
simpleStoreBlueprint = ISimpleStore(VyperDeployer.deployBlueprint("ExampleBlueprint"));

simpleStoreFactory = ISimpleStoreFactory(VyperDeployer.deployContract("SimpleStoreFactory"));
}

function testGet() public {
Expand All @@ -30,6 +31,13 @@ contract SimpleStoreTest is DSTest {
require(val == 1234);
}

function testBalance() public {
uint256 balance = address(simpleStorePayable).balance;
uint256 val = simpleStorePayable.get();

require(balance == val);
}

function testStore(uint256 _val) public {
simpleStore.store(_val);
uint256 val = simpleStore.get();
Expand Down
11 changes: 11 additions & 0 deletions vyper_contracts/SimpleStorePayable.vy
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

val: uint256

@external
@payable
def __init__():
self.val = msg.value

@external
def get() -> uint256:
return self.val