Skip to content

Commit

Permalink
foundry latest update (#123)
Browse files Browse the repository at this point in the history
  • Loading branch information
technophile-04 authored Sep 30, 2024
1 parent 4240e17 commit 9091bfc
Show file tree
Hide file tree
Showing 12 changed files with 394 additions and 243 deletions.
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

0 comments on commit 9091bfc

Please sign in to comment.