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

feat: mvp safe liveness module #27

Merged
merged 31 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e9666ec
chore: remove template contracts
Oct 27, 2023
b192995
chore: update package.json
Oct 27, 2023
18ec914
chore: more config files
Oct 30, 2023
0bba422
chore: remove template contracts
0xOneTony Nov 2, 2023
fe35506
feat: adding storage mirror
Nov 3, 2023
63d061a
chore: comments
Nov 3, 2023
ba9ff12
fix: typo
Nov 3, 2023
facd37b
feat: adding storage mirror (#2)
0xOneTony Nov 13, 2023
8256551
feat: update storage mirror guard (#3)
0xOneTony Nov 15, 2023
38fbdfc
feat: add GuardCallbackModule (#4)
excaliborr Nov 15, 2023
7e653b4
feat: e2e base (#5)
0xOneTony Nov 16, 2023
5abe1c2
chore: update readme (#7)
0xOneTony Nov 20, 2023
3e911f7
feat: oracle contract (#6)
0xOneTony Nov 20, 2023
2343d59
chore: improve readme (#12)
0xOneTony Nov 21, 2023
0210608
feat: needs-update-guard (#8)
0xOneTony Nov 21, 2023
955bf40
feat: verifier module (#9)
excaliborr Nov 21, 2023
8e55d38
feat: storage mirror root registry (#10)
0xOneTony Nov 21, 2023
a644c07
fix: update datatype (#15)
excaliborr Nov 22, 2023
3a0f90e
fix: update mirror guard (#16)
0xOneTony Nov 22, 2023
39d378f
fix: getting real safe settings data (#18)
excaliborr Nov 22, 2023
28d0193
feat: calculating incentive (#17)
excaliborr Nov 22, 2023
219414e
feat: python scripts for generating proofs (#20)
excaliborr Nov 23, 2023
bf92614
feat: periphery function to do the verification flow in one transacti…
excaliborr Nov 23, 2023
59ac780
feat: deploy scripts (#19)
0xOneTony Nov 23, 2023
7ea5dc2
fix: deploy script (#21)
0xOneTony Nov 23, 2023
ab26a81
feat: mdbook docs (#22)
0xOneTony Nov 23, 2023
82bb744
chore: improve e2e base (#14)
0xOneTony Nov 27, 2023
9a4e1fc
fix: e2e tests deploying to ganache node (#24)
excaliborr Nov 28, 2023
5d5458b
test: e2e verification (#25)
excaliborr Nov 28, 2023
2386f79
fix: repo details (#26)
0xOneTony Nov 28, 2023
dc0d88a
chore: remove codeowners (#28)
0xOneTony Nov 28, 2023
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
20 changes: 17 additions & 3 deletions .env.example
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=
1 change: 0 additions & 1 deletion .github/CODEOWNERS

This file was deleted.

3 changes: 3 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# 🤖 Linear

Closes SAF-XXX
21 changes: 16 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ concurrency:

jobs:
forge:
name: Run Unit and E2E Tests
name: Run Unit and Integration Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand All @@ -27,19 +27,30 @@ jobs:
- name: Install dependencies
run: yarn --frozen-lockfile --network-concurrency 1

- name: Precompile using 0.8.14 and via-ir=false
- name: setup python
uses: actions/setup-python@v4
with:
python-version: '3.10' # install the python version needed

- name: install python packages
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Precompile using 0.8.19 and via-ir=false
run: yarn build

- name: "Create env file"
run: |
touch .env
echo MAINNET_RPC="${{ secrets.MAINNET_RPC }}" >> .env
echo GOERLI_RPC="${{ secrets.GOERLI_RPC }}" >> .env
echo MAINNET_INTEGRATION_TESTS_RPC="${{ secrets.MAINNET_INTEGRATION_TESTS_RPC }}" >> .env
echo SEARCHER_PK="${{ secrets.SEARCHER_PK }}" >> .env
echo MAINNET_DEPLOYER_PK="${{ secrets.MAINNET_DEPLOYER_PK }}" >> .env
cat .env

- name: Run tests
shell: bash
run: yarn test
run: yarn test:integration-workflow

forge-optimized:
name: Run Optimized Unit Tests
Expand Down
13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,18 @@ out-via-ir

# Keep related abi
out/*/*
!out/Greeter.sol/*

# Keep the latest deployment only
broadcast/*/*/*

# Docs build files
docs/book
docs/src/solidity/interfaces
docs/src/static

# Cache for the python scripts
proofs/__pycache__/*

# Deployments for Integration tests
solidity/scripts/deployments/*.json
proofs/proof.json
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
# 1. Build the contracts
# 2. Stage build output
# 2. Lint and stage style improvements
yarn build && git add out && npx lint-staged
yarn build && npx lint-staged
3 changes: 2 additions & 1 deletion .solhint.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"const-name-snakecase": "off",
"no-inline-assembly": "off",
"no-empty-blocks": "off",
"func-named-parameters": ["error", 4],
"private-vars-leading-underscore": ["warn", { "strict": false }],
"defi-wonderland/non-state-vars-leading-underscore": ["warn"],
"defi-wonderland/contract-data-order": ["warn"],
Expand All @@ -25,4 +26,4 @@
"defi-wonderland/wonder-var-name-mixedcase": ["warn"],
"avoid-low-level-calls": "off"
}
}
}
32 changes: 32 additions & 0 deletions .solhint.tests.json
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"
}
}
3 changes: 3 additions & 0 deletions .solhintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
cache
out
134 changes: 64 additions & 70 deletions README.md
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.
38 changes: 38 additions & 0 deletions build-docs.sh
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
14 changes: 14 additions & 0 deletions docs/src/SUMMARY.md
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)
1 change: 1 addition & 0 deletions docs/src/content/smart-contracts/addresses.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Addresses
Loading