├── .env.example ├── .gas-snapshot ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── GETTING_STARTED.md ├── LICENSE ├── README.md ├── foundry.toml ├── public └── readme.jpg ├── script └── Deploy.s.sol ├── src └── Greeter.sol ├── test └── Greeter.t.sol └── utils ├── flatten.sh ├── rename.sh ├── run_script.sh └── run_script_local.sh /.env.example: -------------------------------------------------------------------------------- 1 | # RPC URL sourced by scripts 2 | RPC_URL= 3 | 4 | # The deployment private key sourced by scripts 5 | DEPLOYER_KEY= 6 | -------------------------------------------------------------------------------- /.gas-snapshot: -------------------------------------------------------------------------------- 1 | GreeterTest:testSetGm() (gas: 107432) 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: [push] 4 | 5 | jobs: 6 | tests: 7 | name: Forge Testing 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | with: 12 | submodules: recursive 13 | - uses: foundry-rs/foundry-toolchain@v1 14 | with: 15 | version: nightly 16 | - name: dependencies 17 | run: forge install 18 | - name: tests 19 | run: forge test 20 | 21 | snapshot: 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@v3 25 | with: 26 | submodules: recursive 27 | - uses: foundry-rs/foundry-toolchain@v1 28 | with: 29 | version: nightly 30 | - name: dependencies 31 | run: forge install 32 | - name: check contract sizes 33 | run: forge build --sizes 34 | - name: check gas snapshots 35 | run: forge snapshot --check 36 | 37 | # slither: 38 | # runs-on: ubuntu-latest 39 | # steps: 40 | # - uses: actions/checkout@v3 41 | # with: 42 | # submodules: recursive 43 | # - name: slither 44 | # uses: crytic/slither-action@v0.2.0 45 | 46 | scripts: 47 | strategy: 48 | fail-fast: true 49 | name: Run Unix Scripts 50 | runs-on: ubuntu-latest 51 | steps: 52 | - uses: actions/checkout@v3 53 | with: 54 | submodules: recursive 55 | - uses: foundry-rs/foundry-toolchain@v1 56 | with: 57 | version: nightly 58 | - name: dependencies 59 | run: forge build --sizes 60 | continue-on-error: true 61 | - name: Run scripts 62 | run: | 63 | ls -lsa 64 | ls script/ 65 | for file in script/*; do 66 | forge script $file 67 | done -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | cache/ 2 | out/ 3 | 4 | # Ignore Environment Variables! 5 | .env 6 | .env.prod 7 | 8 | # Ignore all vscode settings 9 | .vscode/ 10 | 11 | # Ignore flattened files 12 | flattened.txt 13 | 14 | broadcast 15 | 16 | # Ignore local misc files 17 | .DS_Store 18 | *.pem 19 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | [submodule "lib/solmate"] 5 | path = lib/solmate 6 | url = https://github.com/transmissions11/solmate 7 | -------------------------------------------------------------------------------- /GETTING_STARTED.md: -------------------------------------------------------------------------------- 1 | ## Getting Started 2 | 3 | This is a guide to get you started with [refcell/femplate](https://github.com/refcell/femplate). 4 | 5 | ### Installing 6 | 7 | Click [`use this template`](https://github.com/refcell/femplate/generate) to create a new repository with this repo as the initial state. 8 | 9 | Or, if your repo already exists, run: 10 | ```sh 11 | forge init --template https://github.com/refcell/femplate 12 | git submodule update --init --recursive 13 | forge install 14 | ``` 15 | 16 | Run `./utils/rename.sh` to rename all instances of `femplate` with the name of your project/repository. 17 | 18 | 19 | ### First time with Forge/Foundry? 20 | 21 | See the official Foundry installation [instructions](https://github.com/foundry-rs/foundry/blob/master/README.md#installation). 22 | 23 | Then, install the [foundry](https://github.com/foundry-rs/foundry) toolchain installer (`foundryup`) with: 24 | ```bash 25 | curl -L https://foundry.paradigm.xyz | bash 26 | ``` 27 | 28 | Now that you've installed the `foundryup` binary, 29 | anytime you need to get the latest `forge` or `cast` binaries, 30 | you can run `foundryup`. 31 | 32 | So, simply execute: 33 | ```bash 34 | foundryup 35 | ``` 36 | 37 | 🎉 Foundry is installed! 🎉 38 | 39 | 40 | ### Writing Tests with Foundry 41 | 42 | With [Foundry](https://github.com/foundry-rs/foundry), all tests are written in Solidity! 🥳 43 | 44 | Create a test file for your contract in the `test/` directory. 45 | 46 | For example, [`src/Greeter.sol`](./src/Greeter.sol) has its test file defined in [`./test/Greeter.t.sol`](./test/Greeter.t.sol). 47 | 48 | To learn more about writing tests in Solidity for Foundry, reference Rari Capital's [solmate](https://github.com/Rari-Capital/solmate/tree/main/src/test) repository created by [@transmissions11](https://twitter.com/transmissions11). 49 | 50 | ### Configure Foundry 51 | 52 | Using [foundry.toml](./foundry.toml), Foundry is easily configurable. 53 | 54 | For a full list of configuration options, see the Foundry [configuration documentation](https://github.com/foundry-rs/foundry/blob/master/config/README.md#all-options). 55 | 56 | 57 | ### That's it! 58 | 59 | Now you are all set up to start building your project with femplate! 60 | 61 | Navigate back to the [Readme](./README.md) to resume your setup! 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 asnared 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # femplate • [![tests](https://github.com/refcell/femplate/actions/workflows/ci.yml/badge.svg?label=tests)](https://github.com/refcell/femplate/actions/workflows/ci.yml) ![license](https://img.shields.io/github/license/refcell/femplate?label=license) ![solidity](https://img.shields.io/badge/solidity-^0.8.17-lightgrey) 4 | 5 | A **Clean**, **Robust** Template for Foundry Projects. 6 | 7 | ### Usage 8 | 9 | **Building & Testing** 10 | 11 | Build the foundry project with `forge build`. Then you can run tests with `forge test`. 12 | 13 | **Deployment & Verification** 14 | 15 | Inside the [`utils/`](./utils/) directory are a few preconfigured scripts that can be used to deploy and verify contracts. 16 | 17 | Scripts take inputs from the cli, using silent mode to hide any sensitive information. 18 | 19 | _NOTE: These scripts are required to be _executable_ meaning they must be made executable by running `chmod +x ./utils/*`._ 20 | 21 | _NOTE: these scripts will prompt you for the contract name and deployed addresses (when verifying). Also, they use the `-i` flag on `forge` to ask for your private key for deployment. This uses silent mode which keeps your private key from being printed to the console (and visible in logs)._ 22 | 23 | 24 | ### I'm new, how do I get started? 25 | 26 | We created a guide to get you started with: [GETTING_STARTED.md](./GETTING_STARTED.md). 27 | 28 | 29 | ### Blueprint 30 | 31 | ```txt 32 | lib 33 | ├─ forge-std — https://github.com/foundry-rs/forge-std 34 | ├─ solmate — https://github.com/transmissions11/solmate 35 | scripts 36 | ├─ Deploy.s.sol — Example Contract Deployment Script 37 | src 38 | ├─ Greeter — Example Contract 39 | test 40 | └─ Greeter.t — Example Contract Tests 41 | ``` 42 | 43 | 44 | ### Notable Mentions 45 | 46 | - [femplate](https://github.com/refcell/femplate) 47 | - [foundry](https://github.com/foundry-rs/foundry) 48 | - [solmate](https://github.com/Rari-Capital/solmate) 49 | - [forge-std](https://github.com/brockelmore/forge-std) 50 | - [forge-template](https://github.com/foundry-rs/forge-template) 51 | - [foundry-toolchain](https://github.com/foundry-rs/foundry-toolchain) 52 | 53 | 54 | ### Disclaimer 55 | 56 | _These smart contracts are being provided as is. No guarantee, representation or warranty is being made, express or implied, as to the safety or correctness of the user interface or the smart contracts. They have not been audited and as such there can be no assurance they will work as intended, and users may experience delays, failures, errors, omissions, loss of transmitted information or loss of funds. The creators are not liable for any of the foregoing. Users should proceed with caution and use at their own risk._ 57 | 58 | See [LICENSE](./LICENSE) for more details. 59 | -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | # Foundry Configuration File 2 | # Default definitions: https://github.com/gakonst/foundry/blob/b7917fa8491aedda4dd6db53fbb206ea233cd531/config/src/lib.rs#L782 3 | # See more config options at: https://github.com/gakonst/foundry/tree/master/config 4 | 5 | [profile.default] 6 | solc_version = '0.8.17' 7 | auto_detect_solc = false 8 | optimizer_runs = 1_000 9 | -------------------------------------------------------------------------------- /public/readme.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refcell/femplate/916a78fa997a5b2899eb5f8fa3ec774b04a96ab7/public/readme.jpg -------------------------------------------------------------------------------- /script/Deploy.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.17; 3 | 4 | import {Script} from 'forge-std/Script.sol'; 5 | 6 | import {Greeter} from "src/Greeter.sol"; 7 | 8 | /// @notice A very simple deployment script 9 | contract Deploy is Script { 10 | 11 | /// @notice The main script entrypoint 12 | /// @return greeter The deployed contract 13 | function run() external returns (Greeter greeter) { 14 | vm.startBroadcast(); 15 | greeter = new Greeter("GM"); 16 | vm.stopBroadcast(); 17 | } 18 | } -------------------------------------------------------------------------------- /src/Greeter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.17; 3 | 4 | import { ERC20 } from "solmate/tokens/ERC20.sol"; 5 | 6 | /// @title Greeter 7 | contract Greeter { 8 | string public greeting; 9 | address public owner; 10 | 11 | // CUSTOMS 12 | error BadGm(); 13 | event GMEverybodyGM(); 14 | 15 | constructor(string memory newGreeting) { 16 | greeting = newGreeting; 17 | owner = msg.sender; 18 | } 19 | 20 | function gm(string memory myGm) external returns(string memory greet) { 21 | if (keccak256(abi.encodePacked((myGm))) != keccak256(abi.encodePacked((greet = greeting)))) revert BadGm(); 22 | emit GMEverybodyGM(); 23 | } 24 | 25 | function setGreeting(string memory newGreeting) external { 26 | greeting = newGreeting; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/Greeter.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.17; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | import {Greeter} from "src/Greeter.sol"; 7 | 8 | contract GreeterTest is Test { 9 | using stdStorage for StdStorage; 10 | 11 | Greeter greeter; 12 | 13 | event GMEverybodyGM(); 14 | 15 | function setUp() external { 16 | greeter = new Greeter("gm"); 17 | } 18 | 19 | // VM Cheatcodes can be found in ./lib/forge-std/src/Vm.sol 20 | // Or at https://github.com/foundry-rs/forge-std 21 | function testSetGm() external { 22 | // slither-disable-next-line reentrancy-events,reentrancy-benign 23 | greeter.setGreeting("gm gm"); 24 | 25 | // Expect the GMEverybodyGM event to be fired 26 | vm.expectEmit(true, true, true, true); 27 | emit GMEverybodyGM(); 28 | // slither-disable-next-line unused-return 29 | greeter.gm("gm gm"); 30 | 31 | // Expect the gm() call to revert 32 | vm.expectRevert(abi.encodeWithSignature("BadGm()")); 33 | // slither-disable-next-line unused-return 34 | greeter.gm("gm"); 35 | 36 | // We can read slots directly 37 | uint256 slot = stdstore.target(address(greeter)).sig(greeter.owner.selector).find(); 38 | assertEq(slot, 1); 39 | bytes32 owner = vm.load(address(greeter), bytes32(slot)); 40 | assertEq(address(this), address(uint160(uint256(owner)))); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /utils/flatten.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Read the contract name 4 | echo Which contract do you want to flatten \(eg Greeter\)? 5 | read contract 6 | 7 | # Remove an existing flattened contracts 8 | rm -rf flattened.txt 9 | 10 | # FLATTEN 11 | forge flatten ./src/${contract}.sol > flattened.txt -------------------------------------------------------------------------------- /utils/rename.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Make sed command compatible in both Mac and Linux environments 4 | # Reference: https://stackoverflow.com/a/38595160/8696958 5 | sedi () { 6 | sed --version >/dev/null 2>&1 && sed -i -- "$@" || sed -i "" "$@" 7 | } 8 | 9 | # Read the new repo name 10 | echo Enter your new repo name: 11 | read repo 12 | 13 | # Rename instances of "femplate" to the new repo name in README.md 14 | sedi 's/femplate/'${repo}'/g' 'README.md' 15 | sedi 's/.'${repo}'..https:\/\/github.com\/abigger87\/'${repo}'./[femplate](https:\/\/github.com\/abigger87\/femplate)/g' 'README.md' 16 | -------------------------------------------------------------------------------- /utils/run_script.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Read the RPC URL 4 | source .env 5 | 6 | # Read script 7 | echo Which script do you want to run? 8 | read script 9 | 10 | # Read script arguments 11 | echo Enter script arguments, or press enter if none: 12 | read -ra args 13 | 14 | # Run the script 15 | echo Running Script: $script... 16 | 17 | # Run the script with interactive inputs 18 | forge script $script \ 19 | --rpc-url $RPC_URL \ 20 | --broadcast \ 21 | -vvvv \ 22 | --private-key $DEPLOYER_KEY \ 23 | $args 24 | -------------------------------------------------------------------------------- /utils/run_script_local.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Read the RPC URL 4 | source .env 5 | 6 | ## Fork Mainnet 7 | echo Please wait a few seconds for anvil to fork mainnet and run locally... 8 | anvil --fork-url $RPC_URL & 9 | 10 | # Wait for anvil to fork 11 | sleep 5 12 | 13 | # Read script 14 | echo Which script do you want to run? 15 | read script 16 | 17 | # Read script arguments 18 | echo Enter script arguments, or press enter if none: 19 | read -ra args 20 | 21 | # Run the script 22 | echo Running Script: $script... 23 | 24 | # We specify the anvil url as http://localhost:8545 25 | # We need to specify the sender for our local anvil node 26 | forge script $script \ 27 | --fork-url http://localhost:8545 \ 28 | --broadcast \ 29 | -vvvv \ 30 | --sender 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 \ 31 | --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ 32 | $args 33 | 34 | # Once finished, we want to kill our anvil instance running in the background 35 | trap "exit" INT TERM 36 | trap "kill 0" EXIT 37 | --------------------------------------------------------------------------------