Skip to content

Commit

Permalink
Merge pull request #7 from solidity-labs-io/ci
Browse files Browse the repository at this point in the history
CI + linter + prettier + husky
  • Loading branch information
ElliotFriedman authored Dec 19, 2023
2 parents ba951f9 + abf6460 commit c3dd1d5
Show file tree
Hide file tree
Showing 18 changed files with 2,341 additions and 141 deletions.
89 changes: 89 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: "CI"

env:
FOUNDRY_PROFILE: "ci"

on:
workflow_dispatch:
pull_request:
push:
branches:
- "main"

jobs:
lint:
runs-on: "ubuntu-latest"
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
with:
submodules: "recursive"

- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"

- name: "Install Node.js"
uses: "actions/setup-node@v3"
with:
node-version: "lts/*"

- name: "Install the Node.js dependencies"
run: "npm install"

- name: "Lint the contracts"
run: "npm run lint"

- name: "Add lint summary"
run: |
echo "## Lint result" >> $GITHUB_STEP_SUMMARY
echo "✅ Passed" >> $GITHUB_STEP_SUMMARY
build:
runs-on: "ubuntu-latest"
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
with:
submodules: "recursive"

- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"

- name: "Build the contracts and print their size"
run: "forge build --sizes"

- name: "Add build summary"
run: |
echo "## Build result" >> $GITHUB_STEP_SUMMARY
echo "✅ Passed" >> $GITHUB_STEP_SUMMARY
test:
needs: ["lint", "build"]
runs-on: "ubuntu-latest"
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
with:
submodules: "recursive"

- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"

- name: "Show the Foundry config"
run: "forge config"

- name:
"Generate a fuzz seed that changes weekly to avoid burning through RPC
allowance"
run: >
echo "FOUNDRY_FUZZ_SEED=$(
echo $(($EPOCHSECONDS - $EPOCHSECONDS % 604800))
)" >> $GITHUB_ENV
- name: "Run the tests"
run: "forge test"

- name: "Add test summary"
run: |
echo "## Tests result" >> $GITHUB_STEP_SUMMARY
echo "✅ Passed" >> $GITHUB_STEP_SUMMARY
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ cache/

out/

node_modules/

.env
5 changes: 5 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run prettier:write
npm run lint
14 changes: 14 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# directories
broadcast
cache
coverage
lib
node_modules
out

# files
*.env
*.log
.DS_Store
lcov.info
package-lock.json
21 changes: 21 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"plugins": ["prettier-plugin-solidity"],
"overrides": [
{
"files": "*.sol",
"options": {
"parser": "solidity-parse",
"printWidth": 120,
"tabWidth": 4,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": false
}
}
],
"tabWidth": 4,
"printWidth": 120,
"trailingComma": "all",
"singleQuote": false,
"semi": true
}
19 changes: 19 additions & 0 deletions .solhintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{"extends": "solhint:recommended",
"rules": {
"compiler-version": ["error", ">=0.8.19"],
"func-name-mixedcase": "off",
"func-visibility": ["error", { "ignoreConstructors": true }],
"max-line-length": "off",
"named-parameters-mapping": "warn",
"no-console": "off",
"not-rely-on-time": "off",
"one-contract-per-file": "off",
"no-inline-assembly": "off",
"custom-errors": "off",
"no-empty-blocks": "off",
"var-name-mixedcase": "off",
"no-global-import": "off",
"reason-string": "off",
"immutable-vars-naming": "off"
}
}
94 changes: 70 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# Overview

This is a standard template for creating and managing a smart contract system with foundry. It provides scaffolding for both managing and creating system deployments and governance proposals.
This is a standard template for creating and managing a smart contract system
with foundry. It provides scaffolding for both managing and creating system
deployments and governance proposals.

## Design Philosophy

This template aims to create a system to generate governance proposals and deployments in a unified framework so that integration and unit tests can leverage the system exactly as it will exist once deployed on mainnet. This way, entire categories of bugs can be eliminated such as deploy script errors and governance proposal errors.
This template aims to create a system to generate governance proposals and
deployments in a unified framework so that integration and unit tests can
leverage the system exactly as it will exist once deployed on mainnet. This way,
entire categories of bugs can be eliminated such as deploy script errors and
governance proposal errors.

A proposal type has multiple actions.

Expand All @@ -26,30 +32,53 @@ A proposal type has multiple actions.
function printProposalActionSteps() external;
```

`Deploy`, creates a new smart contract on whichever network the script is pointed at.
`Deploy`, creates a new smart contract on whichever network the script is
pointed at.

`After deploy` actions such as wiring deployed contracts together, calling initialize, etc.
`After deploy` actions such as wiring deployed contracts together, calling
initialize, etc.

`After deploy setup` is any setup that needs to be done after all contracts have been deployed and wired together, such as sending funds to a contract using forge's `deal` function. This step is usually only done for simulations and not run when a proposal is broadcast to a network.
`After deploy setup` is any setup that needs to be done after all contracts have
been deployed and wired together, such as sending funds to a contract using
forge's `deal` function. This step is usually only done for simulations and not
run when a proposal is broadcast to a network.

`Build` the proposal. This is where the proposal calldata is built.

`Run` the proposal. This is where the proposal execution is simulated against a chainforked mainnet.
`Run` the proposal. This is where the proposal execution is simulated against a
chainforked mainnet.

`Teardown` the proposal. This is where any post proposal state changes are made if needed. This is a step that should only run when simulating a proposal, it should never be run during a script broadcast.
`Teardown` the proposal. This is where any post proposal state changes are made
if needed. This is a step that should only run when simulating a proposal, it
should never be run during a script broadcast.

`Validation` of the state after the proposal is run. This is where all deployed or modified contracts are checked to ensure they are in the correct state. For a deployment, this is where the deployed contract is checked to ensure all state variables were properly set. For a proposal, this is where the proposal targets are checked to ensure they are in the correct state. For a proposal that does a deployment and governance proposal/action, both the deployed contract(s) and the proposal target(s) are checked.
`Validation` of the state after the proposal is run. This is where all deployed
or modified contracts are checked to ensure they are in the correct state. For a
deployment, this is where the deployed contract is checked to ensure all state
variables were properly set. For a proposal, this is where the proposal targets
are checked to ensure they are in the correct state. For a proposal that does a
deployment and governance proposal/action, both the deployed contract(s) and the
proposal target(s) are checked.

`Print proposal action steps` This is a helper function to print out the steps that will be taken when a proposal is run. This step also logs any governance proposal calldata that is generated.
`Print proposal action steps` This is a helper function to print out the steps
that will be taken when a proposal is run. This step also logs any governance
proposal calldata that is generated.

Each action type in the system is loosely coupled or decoupled. Actions build and run are tightly coupled. If run is called, build must be called first. If build is called, run should be called after. All other actions are decoupled, but run sequentially in their declaration order.
Each action type in the system is loosely coupled or decoupled. Actions build
and run are tightly coupled. If run is called, build must be called first. If
build is called, run should be called after. All other actions are decoupled,
but run sequentially in their declaration order.

## Usage

To deploy a new system, create a new contract that inherits the [Proposal](./proposals/proposalTypes/Proposal.sol) contract and implements the [IProposal](./proposals/proposalTypes/IProposal.sol) interface. Any actions that are unneeded should be left blank.
To deploy a new system, create a new contract that inherits the
[Proposal](./proposals/proposalTypes/Proposal.sol) contract and implements the
[IProposal](./proposals/proposalTypes/IProposal.sol) interface. Any actions that
are unneeded should be left blank.


Before running the script, environment variables should be set. The following environment variables are used in the system, all of them set to true by default:
Before running the script, environment variables should be set. The following
environment variables are used in the system, all of them set to true by
default:

```
DEBUG
Expand All @@ -63,7 +92,9 @@ DO_VALIDATE
DO_PRINT
```

to change them, set only the unneeded actions to false in the shell before running the script:
to change them, set only the unneeded actions to false in the shell before
running the script:

```
export DEBUG=false
export DO_DEPLOY=false
Expand All @@ -76,15 +107,20 @@ export DO_VALIDATE=false
export DO_PRINT=false
```

Actions build, run, teardown, validate and print will never be run when a proposal is broadcast to a network. They are only run when simulating a proposal or after the braodcast has been run.
Actions build, run, teardown, validate and print will never be run when a
proposal is broadcast to a network. They are only run when simulating a proposal
or after the braodcast has been run.

If deploying a new system, the following environment variables must be set.
If deploying a new system, the following environment variables must be set.

- `ETH_RPC_URL` rpc provider endpoint.
- `DEPLOYER_KEY` is the private key encoded in hex and should be 64 characters.
- `ETHERSCAN_API_KEY` is the etherscan api key used to verify the deployed contracts on etherscan after it is deployed.
- `DEPLOYER_KEY` is the private key encoded in hex and should be 64 characters.
- `ETHERSCAN_API_KEY` is the etherscan api key used to verify the deployed
contracts on etherscan after it is deployed.

Then, once the proposal has been created, run the following command to deploy the system/generate the calldata for the proposal and validate if the flag is set to true:
Then, once the proposal has been created, run the following command to deploy
the system/generate the calldata for the proposal and validate if the flag is
set to true:

```
forge script PathToProposal.sol:ProposalContractName \
Expand All @@ -94,8 +130,18 @@ forge script PathToProposal.sol:ProposalContractName \

## Addresses Contract

The addresses contract is a contract that stores all the addresses of the deployed contracts. It is used to pass the addresses of the deployed contracts to the proposal contract. It is also used to store the addresses of the deployed contracts after the proposal has been run.

Deployed contract addresses, as well as their name and respective networks are stored in the [Addresses.json](./addresses/Addresses.json) file.

Contracts with the same name can be stored in the Addresses.json as long as there is no overlap in the networks they are deployed on. For example, if there is a contract named `Foo` that is deployed on mainnet and a contract named `Foo` that is deployed on rinkeby, both can be stored in the Addresses.json file. However, if there is a contract named `Foo` that is deployed on mainnet twice, only one of them can be stored in the `Addresses.json` file, otherwise there will be a revert during construction.
The addresses contract is a contract that stores all the addresses of the
deployed contracts. It is used to pass the addresses of the deployed contracts
to the proposal contract. It is also used to store the addresses of the deployed
contracts after the proposal has been run.

Deployed contract addresses, as well as their name and respective networks are
stored in the [Addresses.json](./addresses/Addresses.json) file.

Contracts with the same name can be stored in the Addresses.json as long as
there is no overlap in the networks they are deployed on. For example, if there
is a contract named `Foo` that is deployed on mainnet and a contract named `Foo`
that is deployed on rinkeby, both can be stored in the Addresses.json file.
However, if there is a contract named `Foo` that is deployed on mainnet twice,
only one of them can be stored in the `Addresses.json` file, otherwise there
will be a revert during construction.
42 changes: 21 additions & 21 deletions addresses/Addresses.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
[
{
"address": "0x3dd46846eed8D147841AE162C8425c08BD8E1b41",
"name": "DEV_MULTISIG",
"chainid": 1
},
{
"address": "0x7da82C7AB4771ff031b66538D2fB9b0B047f6CF9",
"name": "TEAM_MULTISIG",
"chainid": 1
},
{
"address": "0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
"name": "PROTOCOL_TIMELOCK",
"chainid": 1
},
{
"address": "0x10A19e7eE7d7F8a52822f6817de8ea18204F2e4f",
"name": "DAO_MULTISIG",
"chainid": 1
}
]
{
"addr": "0x3dd46846eed8D147841AE162C8425c08BD8E1b41",
"name": "DEV_MULTISIG",
"chainId": 1
},
{
"addr": "0x7da82C7AB4771ff031b66538D2fB9b0B047f6CF9",
"name": "TEAM_MULTISIG",
"chainId": 1
},
{
"addr": "0x1a9C8182C09F50C8318d769245beA52c32BE35BC",
"name": "PROTOCOL_TIMELOCK",
"chainId": 1
},
{
"addr": "0x10A19e7eE7d7F8a52822f6817de8ea18204F2e4f",
"name": "DAO_MULTISIG",
"chainId": 1
}
]
Loading

0 comments on commit c3dd1d5

Please sign in to comment.