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

foundry latest update #123

Merged
merged 3 commits into from
Sep 30, 2024
Merged
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
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
DEPLOYER_PRIVATE_KEY=
ETHERSCAN_API_KEY=
ALCHEMY_API_KEY=
# Template for foundry environment variables.

# For local development, copy this file, rename it to .env, and fill in the values.

# We provide default values so developers can start prototyping out of the box,
# but we recommend getting your own API Keys for Production Apps.

# DEPLOYER_PRIVATE_KEY is used while deploying contract.
# On anvil chain the value of it can be empty since we use the prefunded account
# which comes with anvil chain to deploy contract.
# NOTE: You don't need to manually change the value of DEPLOYER_PRIVATE_KEY, it should
# be auto filled when run `yarn generate`.
# Although `.env` is ignored by git, it's still important that you don't paste your
# actual account private key and use the generated one.
# Alchemy rpc URL is used while deploying the contracts to some testnets/mainnets, checkout `foundry.toml` for it's use.
ALCHEMY_API_KEY=oKxs-03sij-U_N0iOlrSsZFr29-IqbuF

# Etherscan API key is used to verify the contract on etherscan.
ETHERSCAN_API_KEY=DNXJA8RX2Q3VZ4URQIWP7Z68CJXQZSC6AW
# Default account for localhost / use "scaffold-eth-custom" if you wish to use a generated account or imported account
ETH_KEYSTORE_ACCOUNT=scaffold-eth-default
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
const contents = () =>
`DEPLOYER_PRIVATE_KEY=
`# Template for foundry environment variables.

# For local development, copy this file, rename it to .env, and fill in the values.

# We provide default values so developers can start prototyping out of the box,
# but we recommend getting your own API Keys for Production Apps.

# DEPLOYER_PRIVATE_KEY is used while deploying contract.
# On anvil chain the value of it can be empty since we use the prefunded account
# which comes with anvil chain to deploy contract.
# NOTE: You don't need to manually change the value of DEPLOYER_PRIVATE_KEY, it should
# be auto filled when run \`yarn generate\`.
# Although \`.env\` is ignored by git, it's still important that you don't paste your
# actual account private key and use the generated one.
# Alchemy rpc URL is used while deploying the contracts to some testnets/mainnets, checkout \`foundry.toml\` for it's use.
ALCHEMY_API_KEY=oKxs-03sij-U_N0iOlrSsZFr29-IqbuF

# Etherscan API key is used to verify the contract on etherscan.
ETHERSCAN_API_KEY=DNXJA8RX2Q3VZ4URQIWP7Z68CJXQZSC6AW
`
# Default account for localhost / use "scaffold-eth-custom" if you wish to use a generated account or imported account
ETH_KEYSTORE_ACCOUNT=scaffold-eth-default`;

export default contents
export default contents;
89 changes: 89 additions & 0 deletions templates/solidity-frameworks/foundry/packages/foundry/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
.PHONY: build deploy generate-abis verify-keystore account chain compile deploy-verify flatten fork format lint test verify

# setup wallet for anvil
setup-anvil-wallet:
shx rm ~/.foundry/keystores/scaffold-eth-default 2>/dev/null; \
cast wallet import --private-key 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6 --unsafe-password 'localhost' scaffold-eth-default

# Start local chain
chain: setup-anvil-wallet
anvil

# Start a fork
fork: setup-anvil-wallet
anvil --fork-url ${FORK_URL} --chain-id 31337

# Build the project
build:
forge build --build-info --build-info-path out/build-info/

# Deploy the project
deploy:
@if [ "$(RPC_URL)" = "localhost" ]; then \
forge script script/Deploy.s.sol --rpc-url localhost --password localhost --broadcast --legacy --ffi; \
else \
forge script script/Deploy.s.sol --rpc-url $(RPC_URL) --broadcast --legacy --ffi; \
fi

# Build and deploy target
build-and-deploy: build deploy generate-abis

# Generate TypeScript ABIs
generate-abis:
node scripts-js/generateTsAbis.js

verify-keystore:
if grep -q "scaffold-eth-default" .env; then \
cast wallet address --password localhost; \
else \
cast wallet address; \
fi

# List account
account:
@node scripts-js/ListAccount.js $$(make verify-keystore)

# Generate a new account
account-generate:
@cast wallet import $(ACCOUNT_NAME) --private-key $$(cast wallet new | grep 'Private key:' | awk '{print $$3}')
@echo "Please update .env file with ETH_KEYSTORE_ACCOUNT=$(ACCOUNT_NAME)"

# Import an existing account
account-import:
@cast wallet import ${ACCOUNT_NAME} --interactive

# Compile contracts
compile:
forge compile

# Deploy and verify
deploy-verify:
@if [ "$(RPC_URL)" = "localhost" ]; then \
forge script script/Deploy.s.sol --rpc-url localhost --password localhost --broadcast --legacy --ffi --verify; \
else \
forge script script/Deploy.s.sol --rpc-url $(RPC_URL) --broadcast --legacy --ffi --verify; \
fi
node scripts-js/generateTsAbis.js

# Flatten contracts
flatten:
forge flatten

# Format code
format:
forge fmt && prettier --write ./scripts-js/**/*.js

# Lint code
lint:
forge fmt --check && prettier --check ./script/**/*.js

# Run tests
test:
forge test

# Verify contracts
verify:
forge script script/VerifyAll.s.sol --ffi --rpc-url $(RPC_URL)

build-and-verify: build verify

35 changes: 19 additions & 16 deletions templates/solidity-frameworks/foundry/packages/foundry/package.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
{
"name": "@se-2/foundry",
"version": "0.0.1",
"type": "module",
"scripts": {
"account": "node script/ListAccount.js",
"chain": "anvil --config-out localhost.json",
"fork": "anvil --fork-url ${0:-mainnet} --chain-id 31337 --config-out localhost.json",
"compile": "forge compile",
"generate": "node script/generateAccount.js",
"flatten": "forge flatten",
"deploy": "forge build --build-info --build-info-path out/build-info/ && forge script script/Deploy.s.sol --rpc-url ${1:-default_network} --broadcast --legacy && node script/generateTsAbis.js",
"deploy:verify": "forge build --build-info --build-info-path out/build-info/ && forge script script/Deploy.s.sol --rpc-url ${1:-default_network} --broadcast --legacy --verify ; node script/generateTsAbis.js",
"verify": "forge build --build-info --build-info-path out/build-info/ && forge script script/VerifyAll.s.sol --ffi --rpc-url ${1:-default_network}",
"lint": "forge fmt --check && prettier --check ./script/**/*.js",
"format": "forge fmt && prettier --write ./script/**/*.js",
"test": "forge test"
},
"devDependencies": {
"@types/prettier": "2",
"@types/qrcode": "1"
"verify-keystore": "make verify-keystore",
"account": "make account",
"account:generate": "make account-generate ACCOUNT_NAME=${1:-scaffold-eth-custom}",
"account:import": "make account-import ACCOUNT_NAME=${1:-scaffold-eth-custom}",
"chain": "make chain",
"compile": "make compile",
"deploy": "make build-and-deploy RPC_URL=${1:-localhost}",
"deploy:verify": "make deploy-verify RPC_URL=${1:-localhost}",
"flatten": "make flatten",
"fork": "make fork FORK_URL=${1:-mainnet}",
"format": "make format",
"lint": "make lint",
"test": "make test",
"verify": "make build-and-verify RPC_URL=${1:-localhost}",
"postinstall": "shx cp -n .env.example .env"
},
"dependencies": {
"dotenv": "~16.3.1",
Expand All @@ -26,5 +26,8 @@
"prettier": "~2.8.8",
"qrcode": "~1.5.3",
"toml": "~3.0.0"
},
"devDependencies": {
"shx": "~0.3.4"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,21 @@ import { withDefaults } from "../../../../../utils.js";
const content = ({ deploymentsScriptsImports, deploymentsLogic }) => `//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "../contracts/YourContract.sol";
import "./DeployHelpers.s.sol";
import { DeployYourContract } from "./DeployYourContract.s.sol";
${deploymentsScriptsImports.filter(Boolean).join("\n")}

contract DeployScript is ScaffoldETHDeploy {
error InvalidPrivateKey(string);
function run() external {
DeployYourContract deployYourContract = new DeployYourContract();
deployYourContract.run();

function run() external {
uint256 deployerPrivateKey = setupLocalhostEnv();
if (deployerPrivateKey == 0) {
revert InvalidPrivateKey(
"You don't have a deployer account. Make sure you have set DEPLOYER_PRIVATE_KEY in .env or use \`yarn generate\` to generate a new random account"
);
}
vm.startBroadcast(deployerPrivateKey);
${deploymentsLogic.filter(Boolean).join("\n")}

YourContract yourContract = new YourContract(
vm.addr(deployerPrivateKey)
);
console.logString(
string.concat(
"YourContract deployed at: ",
vm.toString(address(yourContract))
)
);

vm.stopBroadcast();

${deploymentsLogic.filter(Boolean).join("\n")}

/**
* This function generates the file containing the contracts Abi definitions.
* These definitions are used to derive the types needed in the custom scaffold-eth hooks, for example.
* This function should be called last.
*/
exportDeployments();
}

function test() public {}
// deploy more contracts here
// DeployMyContract deployMyContract = new DeployMyContract();
// deployMyContract.run();
}
}`;

export default withDefaults(content, {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

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

contract ScaffoldETHDeploy is Script {
error InvalidChain();
error DeployerHasNoBalance();
error InvalidPrivateKey(string);

event AnvilSetBalance(address account, uint256 amount);
event FailedAnvilRequest();

struct Deployment {
string name;
Expand All @@ -15,18 +20,38 @@ contract ScaffoldETHDeploy is Script {
string root;
string path;
Deployment[] public deployments;
uint256 constant ANVIL_BASE_BALANCE = 10000 ether;

/// @notice The deployer address for every run
address deployer;

function setupLocalhostEnv() internal returns (uint256 localhostPrivateKey) {
if (block.chainid == 31337) {
root = vm.projectRoot();
path = string.concat(root, "/localhost.json");
string memory json = vm.readFile(path);
bytes memory mnemonicBytes = vm.parseJson(json, ".wallet.mnemonic");
string memory mnemonic = abi.decode(mnemonicBytes, (string));
return vm.deriveKey(mnemonic, 0);
} else {
return vm.envUint("DEPLOYER_PRIVATE_KEY");
/// @notice Use this modifier on your run() function on your deploy scripts
modifier ScaffoldEthDeployerRunner() {
deployer = _startBroadcast();
if (deployer == address(0)) {
revert InvalidPrivateKey("Invalid private key");
}
_;
_stopBroadcast();
exportDeployments();
}

function _startBroadcast() internal returns (address) {
vm.startBroadcast();
(, address _deployer,) = vm.readCallers();

if (block.chainid == 31337 && _deployer.balance == 0) {
try this.anvil_setBalance(_deployer, ANVIL_BASE_BALANCE) {
emit AnvilSetBalance(_deployer, ANVIL_BASE_BALANCE);
} catch {
emit FailedAnvilRequest();
}
}
return _deployer;
}

function _stopBroadcast() internal {
vm.stopBroadcast();
}

function exportDeployments() internal {
Expand Down Expand Up @@ -61,6 +86,30 @@ contract ScaffoldETHDeploy is Script {
return getChain(block.chainid);
}

function anvil_setBalance(address addr, uint256 amount) public {
string memory addressString = vm.toString(addr);
string memory amountString = vm.toString(amount);
string memory requestPayload = string.concat(
'{"method":"anvil_setBalance","params":["',
addressString,
'","',
amountString,
'"],"id":1,"jsonrpc":"2.0"}'
);

string[] memory inputs = new string[](8);
inputs[0] = "curl";
inputs[1] = "-X";
inputs[2] = "POST";
inputs[3] = "http://localhost:8545";
inputs[4] = "-H";
inputs[5] = "Content-Type: application/json";
inputs[6] = "--data";
inputs[7] = requestPayload;

vm.ffi(inputs);
}

function findChainName() public returns (string memory) {
uint256 thisChainId = block.chainid;
string[2][] memory allRpcUrls = vm.rpcUrls();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "../contracts/YourContract.sol";
import "./DeployHelpers.s.sol";

contract DeployYourContract is ScaffoldETHDeploy {
// use `deployer` from `ScaffoldETHDeploy`
function run() external ScaffoldEthDeployerRunner {
YourContract yourContract = new YourContract(deployer);
console.logString(string.concat("YourContract deployed at: ", vm.toString(address(yourContract))));
}
}
Loading
Loading