generated from defi-wonderland/solidity-foundry-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: mvp safe liveness module (#27)
Includes all the: - Smart contracts logic - Close to 100% unit test coverage - Integration tests - Deployment scripts - Documentation
- Loading branch information
Showing
65 changed files
with
4,593 additions
and
2,145 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,21 @@ | ||
MAINNET_RPC= | ||
GOERLI_RPC= | ||
OPTIMISM_RPC= | ||
OPTIMISM_GOERLI_RPC= | ||
|
||
# Deployer private key for the Integrations Tests | ||
MAINNET_DEPLOYER_PK= | ||
# Searcher PK for Integration Tests | ||
SEARCHER_PK= | ||
|
||
GOERLI_RPC= | ||
GOERLI_DEPLOYER_PK= | ||
# Mainnet rpc for the Integration Tests, should be the ganache url | ||
MAINNET_INTEGRATION_TESTS_RPC= | ||
|
||
## For deployment scripts | ||
DEPLOYER_MAINNNET_PRIVATE_KEY= | ||
DEPLOYER_GOERLI_PRIVATE_KEY= | ||
DEPLOYER_OPTIMISM_PRIVATE_KEY= | ||
DEPLOYER_OPTIMISM_GOERLI_PRIVATE_KEY= | ||
STORAGE_MIRROR_ADDRESS= | ||
|
||
ETHERSCAN_API_KEY= | ||
ETHERSCAN_API_KEY= |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# 🤖 Linear | ||
|
||
Closes SAF-XXX |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"extends": "solhint:recommended", | ||
"plugins": ["defi-wonderland"], | ||
"rules": { | ||
"compiler-version": ["off"], | ||
"constructor-syntax": "warn", | ||
"quotes": ["error", "single"], | ||
"func-visibility": ["warn", { "ignoreConstructors": true }], | ||
"not-rely-on-time": "off", | ||
"func-name-mixedcase": "off", | ||
"var-name-mixedcase": "off", | ||
"const-name-snakecase": "off", | ||
"no-inline-assembly": "off", | ||
"no-empty-blocks": "off", | ||
"contract-name-camelcase": "off", | ||
"event-name-camelcase": "off", | ||
"func-named-parameters": "off", | ||
"no-global-import": "off", | ||
"max-states-count": "off", | ||
"private-vars-leading-underscore": ["warn", { "strict": false }], | ||
"defi-wonderland/non-state-vars-leading-underscore": ["warn"], | ||
"defi-wonderland/contract-data-order": ["warn"], | ||
"defi-wonderland/enum-name-camelcase": ["warn"], | ||
"defi-wonderland/immutable-name-snakecase": ["warn"], | ||
"defi-wonderland/interface-member-order": ["warn"], | ||
"defi-wonderland/interface-starts-with-i": ["warn"], | ||
"defi-wonderland/named-return-values": ["warn"], | ||
"defi-wonderland/struct-name-camelcase": ["warn"], | ||
"defi-wonderland/wonder-var-name-mixedcase": ["warn"], | ||
"avoid-low-level-calls": "off" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
node_modules | ||
cache | ||
out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,107 +1,101 @@ | ||
<img src="https://raw.githubusercontent.com/defi-wonderland/brand/v1.0.0/external/solidity-foundry-boilerplate-banner.png" alt="wonderland banner" align="center" /> | ||
<br /> | ||
# Safe Liveness | ||
|
||
<div align="center"><strong>Start your next Solidity project with Foundry in seconds</strong></div> | ||
<div align="center">A highly scalable foundation focused on DX and best practices</div> | ||
⚠️ The code has not been audited yet, tread with caution. | ||
|
||
<br /> | ||
## Overview | ||
|
||
## Features | ||
Safe-Liveness is a module that will tackle the liveness problem, one of the main challenges faced by smart wallets to improve cross-chain user experience. | ||
|
||
<dl> | ||
<dt>Sample contracts</dt> | ||
<dd>Basic Greeter contract with an external interface.</dd> | ||
Unlike EOAs, smart wallets have configuration settings, which can cause synchronization problems across chains. Consequently, SAFEs on different chains function as separate contracts, even though they may share the same address and configuration parameters during deployment. This problem becomes critical when there’s a change in the owners’ list. | ||
|
||
<dt>Foundry setup</dt> | ||
<dd>Foundry configuration with multiple custom profiles and remappings.</dd> | ||
|
||
<dt>Deployment scripts</dt> | ||
<dd>Sample scripts to deploy contracts on both mainnet and testnet.</dd> | ||
|
||
<dt>Sample e2e & unit tests</dt> | ||
<dd>Example tests showcasing mocking, assertions and configuration for mainnet forking. As well it includes everything needed in order to check code coverage.</dd> | ||
|
||
<dt>Linter</dt> | ||
<dd>Simple and fast solidity linting thanks to forge fmt</a>.</dd> | ||
|
||
<dt>Github workflows CI</dt> | ||
<dd>Run all tests and see the coverage as you push your changes.</dd> | ||
</dl> | ||
We will create a module that can verify Safe ownership based on a storage proof, allowing you to easily broadcast any changes in your Safe to other chains. | ||
|
||
## Setup | ||
|
||
1. Install Foundry by following the instructions from [their repository](https://github.com/foundry-rs/foundry#installation). | ||
2. Copy the `.env.example` file to `.env` and fill in the variables. | ||
3. Install the dependencies by running: `yarn install`. In case there is an error with the commands, run `foundryup` and try them again. | ||
This project uses [Foundry](https://book.getfoundry.sh/). To build it locally, run: | ||
|
||
## Build | ||
|
||
The default way to build the code is suboptimal but fast, you can run it via: | ||
|
||
```bash | ||
```sh | ||
git clone [email protected]:defi-wonderland/safe-liveness.git | ||
cd safe-liveness | ||
yarn install | ||
yarn build | ||
``` | ||
|
||
In order to build a more optimized code ([via IR](https://docs.soliditylang.org/en/v0.8.15/ir-breaking-changes.html#solidity-ir-based-codegen-changes)), run: | ||
## Integration Tests | ||
|
||
```bash | ||
yarn build:optimized | ||
``` | ||
In order to run the integration tests you will need python setup to generate the proofs, ganache running and some enviroment variables. | ||
|
||
## Running tests | ||
1. Set up python and install requirements | ||
|
||
Unit tests should be isolated from any externalities, while E2E usually run in a fork of the blockchain. In this boilerplate you will find example of both. | ||
```sh | ||
python -m pip install --upgrade pip | ||
pip install -r requirements.txt | ||
``` | ||
|
||
In order to run both unit and E2E tests, run: | ||
2. Run ganache | ||
|
||
```bash | ||
yarn test | ||
```sh | ||
yarn ganache | ||
``` | ||
|
||
In order to just run unit tests, run: | ||
3. Set enviroment variables | ||
|
||
```bash | ||
yarn test:unit | ||
``` | ||
`MAINNET_INTEGRATION_TESTS_RPC` should be the ganache endpoint | ||
`MAINNET_DEPLOYER_PK` should be the deployer of the protocol and a safe owner | ||
`SEARCHER_PK` should be the incentivized actor to verify | ||
|
||
In order to run unit tests and run way more fuzzing than usual (5x), run: | ||
4. Run the tests | ||
|
||
```bash | ||
yarn test:unit:deep | ||
```sh | ||
yarn test:integration | ||
``` | ||
|
||
In order to just run e2e tests, run: | ||
### Available Commands | ||
|
||
```bash | ||
yarn test:e2e | ||
``` | ||
| Yarn Command | Description | | ||
| ----------------------- | ---------------------------------------------------------- | | ||
| `yarn build` | Compile all contracts. | | ||
| `yarn coverage` | See `forge coverage` report. | | ||
| `yarn deploy` | Deploy the contracts to Mainnet. | | ||
| `yarn test` | Run all unit and integration tests. | | ||
| `yarn test:unit` | Run unit tests. | | ||
| `yarn test:integration` | Run integration tests. | | ||
| `yarn deploy:mainnet` | Deploys Home Chain contracts to Mainnet | | ||
| `yarn deploy:optimism` | Deploys Non-Home Chain contracts to Optimism | | ||
| `yarn deploy:goerli` | Deploys Home Chain contracts to Goerli | | ||
| `yarn deploy:optimismGoerli`| Deploys Non-Home Chain contracts to Optimism Goerli | | ||
| `yarn docs:build` | Build the docs | | ||
| `yarn docs:run` | Runs the docs, needs mdbook | | ||
| `yarn ganache` | Spawn a ganache instance | | ||
|
||
In order to check your current code coverage, run: | ||
|
||
```bash | ||
yarn coverage | ||
``` | ||
## Smart Contracts | ||
|
||
<br> | ||
### Home Chain | ||
- `UpdateStorageMirrorGuard`: This guard is responsible for calling the GuardCallbackModule when a change in the settings of a safe is executed. | ||
- `GuardCallbackModule`: This contract is a module that is used to save the updated settings to the StorageMirror. | ||
- `StorageMirror`: This contract is a storage of information about the safe’s settings. All safe’s settings changes should be mirrored in this contract and be saved. In the end, this contract’s storage root is gonna be used to see if a proposed update on the non-home chain is valid. | ||
|
||
## Deploy & verify | ||
### Non-Home Chain | ||
- `BlockHeaderOracle`: This contract's purpose is to return the latest stored L1 block header and timestamp. Every X minutes a "magical" off-chain agent provides the latest block header and timestamp. | ||
- `NeedsUpdateGuard`: This guard should prevent the safe from executing any transaction if an update is needed. An update is needed based on the owner's security settings that was inputed. | ||
- `VerifierModule`: This contract is the verifier module that verifies the settings of a safe against the StorageMirror on the home chain. | ||
- `StorageMirrorRootRegistry`: This contract should accept and store storageRoots of the StorageMirror contract in L1. | ||
|
||
### Setup | ||
|
||
Configure the `.env` variables. | ||
## ⚠️ Warnings | ||
|
||
### Goerli | ||
The project is a PoC implementation and should be treated with caution. Bellow we describe some cases that should be taken into account before using the modules/guard. | ||
|
||
```bash | ||
yarn deploy:goerli | ||
``` | ||
- `UpdateStorageMirrorGuard` for the PoC this guard is calling the `GuardCallbackModule` in every call. A possible improvement would be to decode the txData, on the guard `checkTransaction` pre-execute hook, and filter against certain function signatures that change the settings of a Safe to accurately catch the change. | ||
- `NeedsUpdateGuard` this guard on the non-home chain can brick the user's safe, since it will block every tx, if their security settings expire. Also it's worth mentioning that before using the guard the safe owner must verify at least 1 set of settings using the VerifierModule in order for the guard to have a point of reference for the latest verified update. | ||
- `VerifierModule` is executing a safeTx after the verification and update of their settings. This safeTx can become invalid since the signatures passed were created before the change of the settings, in this case the user(s) will need to re-sign the tx manually outside of the UI. A possible improvement would be to have a custom safe app that let's you sign even if you are not a "current owner" but are a "potential future owner" of the "soon-to-be-updated" settings | ||
- `VerifierModule` makes the assumption that the address of the safe is the same on both the home chain, and non-home chain. The current implementation will not work if these addresses are different | ||
|
||
### Mainnet | ||
## Contributors | ||
|
||
```bash | ||
yarn deploy:mainnet | ||
``` | ||
Safe-Liveness was built with ❤️ by [Wonderland](https://defi.sucks). | ||
|
||
The deployments are stored in ./broadcast | ||
Wonderland is a team of top Web3 researchers, developers, and operators who believe that the future needs to be open-source, permissionless, and decentralized. | ||
|
||
See the [Foundry Book for available options](https://book.getfoundry.sh/reference/forge/forge-create.html). | ||
[DeFi sucks](https://defi.sucks), but Wonderland is here to make it better. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#!/bin/bash | ||
|
||
# generate docs in a temporary directory | ||
FOUNDRY_PROFILE=docs forge doc --out tmp/safe-liveness-technical-docs | ||
|
||
# edit generated summary not to have container pages | ||
# - [jobs](solidity/interfaces/jobs/README.md) | ||
# should become | ||
# - [jobs]() | ||
# TODO | ||
|
||
# edit generated summary titles to start with an uppercase letter | ||
# - [jobs]() | ||
# should become | ||
# - [Jobs]() | ||
# TODO | ||
|
||
# edit the SUMMARY after the Interfaces section | ||
# https://stackoverflow.com/questions/67086574/no-such-file-or-directory-when-using-sed-in-combination-with-find | ||
if [[ "$OSTYPE" == "darwin"* ]]; then | ||
sed -i '' -e '/\[Interfaces\]/q' docs/src/SUMMARY.md | ||
else | ||
sed -i -e '/\[Interfaces\]/q' docs/src/SUMMARY.md | ||
fi | ||
# copy the generated SUMMARY, from the tmp directory, without the first 5 lines | ||
# and paste them after the Interfaces section on the original SUMMARY | ||
tail -n +5 tmp/safe-liveness-technical-docs/src/SUMMARY.md >> docs/src/SUMMARY.md | ||
|
||
# delete old generated interfaces docs | ||
rm -rf docs/src/solidity/interfaces | ||
# there are differences in cp and mv behavior between UNIX and macOS when it comes to non-existing directories | ||
# creating the directory to circumvent them | ||
mkdir -p docs/src/solidity/interfaces | ||
# move new generated interfaces docs from tmp to original directory | ||
cp -R tmp/safe-liveness-technical-docs/src/solidity/interfaces docs/src/solidity/ | ||
|
||
# delete tmp directory | ||
rm -rf tmp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<!-- TODO: add links to oracles.rip, to mirror and to twitter --> | ||
|
||
# Overview | ||
|
||
- [Smart Contracts]() | ||
|
||
- [Addresses](content/smart-contracts/addresses.md) | ||
- [Interfaces]() | ||
- [IBlockHeaderOracle](solidity/interfaces/IBlockHeaderOracle.sol/interface.IBlockHeaderOracle.md) | ||
- [IGuardCallbackModule](solidity/interfaces/IGuardCallbackModule.sol/interface.IGuardCallbackModule.md) | ||
- [ISafe](solidity/interfaces/ISafe.sol/interface.ISafe.md) | ||
- [IStorageMirror](solidity/interfaces/IStorageMirror.sol/interface.IStorageMirror.md) | ||
- [IStorageMirrorRootRegistry](solidity/interfaces/IStorageMirrorRootRegistry.sol/interface.IStorageMirrorRootRegistry.md) | ||
- [IVerifierModule](solidity/interfaces/IVerifierModule.sol/interface.IVerifierModule.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Addresses |
Oops, something went wrong.