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

Turn it into a side panel #138

Merged
merged 127 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
127 commits
Select commit Hold shift + click to select a range
1e9988d
per tab panel toggling
jfschwarz Aug 20, 2024
aef4042
fix rules error
jfschwarz Aug 20, 2024
88897b8
assume case-insensitive header rules
jfschwarz Aug 20, 2024
9b3b898
separate background script concerns
jfschwarz Aug 20, 2024
f4dc496
use react-router
jfschwarz Aug 20, 2024
cd3f841
cleanup
jfschwarz Aug 20, 2024
1bebaec
fix public path
jfschwarz Aug 20, 2024
22a3bd7
track pilot sessions across windows and tabs
jfschwarz Aug 21, 2024
4df6748
poc: make injected wallet available to extension
jfschwarz Aug 21, 2024
74cf1c9
solidify connect/useInjectedWallet implementation
jfschwarz Aug 22, 2024
b8cc4b7
sketch implementation for new inject provider bridge
jfschwarz Aug 22, 2024
af943a0
panel live reloading
jfschwarz Aug 22, 2024
932eb17
inject provider & per-window session tracking
jfschwarz Aug 23, 2024
8950563
relay to right window
jfschwarz Aug 23, 2024
f74e62b
route to right window using sender + some messaging fixes
jfschwarz Aug 23, 2024
285c895
fix injected provider
jfschwarz Aug 26, 2024
5805d66
fix injected provider issues
jfschwarz Aug 26, 2024
dafcfe7
wip
jfschwarz Aug 29, 2024
1b0f2f7
use new connect site
jfschwarz Aug 29, 2024
52bf11d
inject the provider script only into tracked tabs
jfschwarz Aug 30, 2024
79817a8
reload tab on panel toggle
jfschwarz Sep 1, 2024
a318e50
fix init concurrency issue
jfschwarz Sep 1, 2024
1ee946e
fix injection (it was running as a contentScript instead of in the co…
jfschwarz Sep 1, 2024
90b710a
migrate routes to extension storage
jfschwarz Sep 2, 2024
5ed7847
small inject fixes
jfschwarz Sep 2, 2024
892cdbc
fix routes hooks
jfschwarz Sep 5, 2024
0d4ddc0
connect state monitoring
jfschwarz Sep 5, 2024
8caf973
correct eip1193 connect/disconnect events
jfschwarz Sep 5, 2024
04640c2
sketch reload perf optimization
jfschwarz Sep 6, 2024
4898ecb
fix some route edit issues
jfschwarz Sep 6, 2024
4bad4d4
fix error from duplicate injections
jfschwarz Sep 6, 2024
9f91efd
make rpc intercept work
jfschwarz Sep 9, 2024
02fcea8
fix issue with duplicate requests
jfschwarz Sep 10, 2024
6b17a9f
make connect wallet work again
jfschwarz Sep 11, 2024
7e14827
only register all background event listeners on onInstalled
jfschwarz Sep 19, 2024
811fdc3
undo using onInstalled listeners
jfschwarz Sep 20, 2024
929075a
prettier log
jfschwarz Sep 20, 2024
959cb56
better labels
jfschwarz Sep 20, 2024
cb18652
always inject connect content script
jfschwarz Sep 30, 2024
bab569d
keep port connection with connect content script
jfschwarz Sep 30, 2024
d6c57e7
cleanup and fix connect button
jfschwarz Sep 30, 2024
d7bcd50
fix: sidepanel wallet connect (#163)
frontendphil Oct 15, 2024
f8d8ad5
chore: disable meta mask connect when injected provider is not connec…
frontendphil Oct 16, 2024
0677e1d
chore: test setup with example app (#165)
frontendphil Oct 16, 2024
c7db14f
chore: open zodiac extension in test (#167)
frontendphil Oct 17, 2024
b10989f
chore: switch to pnpm (#169)
frontendphil Oct 17, 2024
8479031
chore: fix pipelines (#168)
frontendphil Oct 17, 2024
8ba75b8
chore: add tailwind, improve padding (#171)
frontendphil Oct 18, 2024
3d9e812
feat: handle account disconnects (lock wallet) (#170)
frontendphil Oct 21, 2024
2bcfae6
feat: reconnect account (#175)
frontendphil Oct 21, 2024
605c3a6
chore: ts aliases (#177)
frontendphil Oct 22, 2024
69e7bbe
chore: switch example app to pnpm (#178)
frontendphil Oct 22, 2024
0ba3366
feat: handle account unavailability (#176)
frontendphil Oct 23, 2024
7a643a7
chore: update some styles (#181)
frontendphil Oct 23, 2024
bc5b3bd
chore: refactor connect button (#182)
frontendphil Oct 23, 2024
3230ed7
chore: move files for more cohesion (#183)
frontendphil Oct 23, 2024
24d6b48
chore: split react router routes and zodiac routes (#184)
frontendphil Oct 25, 2024
464707e
chore: rename components to make their use clearer (#185)
frontendphil Oct 25, 2024
76edd46
chore: extract and split more things (#188)
frontendphil Oct 28, 2024
f17c8ed
chore: unit test setup for components (#187)
frontendphil Oct 29, 2024
034b64f
chore: extract get current tab utility (#190)
frontendphil Oct 29, 2024
98966ce
chore: add unit tests for session/tab tracking (#191)
frontendphil Oct 30, 2024
12ee930
chore: add unit test for rpc tracking (#192)
frontendphil Oct 30, 2024
56a2d1d
only setup listeners once (#193)
frontendphil Oct 30, 2024
9460cad
chore: put different message types in one place (#195)
frontendphil Nov 1, 2024
7d41bb6
remove default exports (#196)
frontendphil Nov 1, 2024
2cba038
chore: remove global react imports (#197)
frontendphil Nov 1, 2024
20253f0
fix: no errors on panel load (#198)
frontendphil Nov 4, 2024
6a54605
fix: connect wallet on panel start (#199)
frontendphil Nov 7, 2024
5f32746
fix: modify link not working (#200)
frontendphil Nov 7, 2024
193c5d8
chore: highlight configuration errors a bit better (#201)
frontendphil Nov 13, 2024
4c7553a
workaround for safe kit builds (#203)
frontendphil Nov 13, 2024
2e97c91
upgrade safe protocol-kit and fix tooling (#180)
jfschwarz Nov 13, 2024
6c015d0
fix: more communication issues (#204)
frontendphil Nov 14, 2024
f0c1276
chore: make init port a hook (#205)
frontendphil Nov 14, 2024
f12c99a
do not require a pilot open button to be present on every page (#206)
frontendphil Nov 14, 2024
55f3379
fix: cannot reconnect wallet (#207)
frontendphil Nov 15, 2024
9a9b9b5
fix layout of transaction list (#208)
frontendphil Nov 15, 2024
4297fcd
feat: tell user when pilot is not ready (#209)
frontendphil Nov 15, 2024
aaed819
fix: provider is reset after some time (#210)
frontendphil Nov 18, 2024
493e352
use tailwind for hint markup (#211)
frontendphil Nov 18, 2024
2b5395f
simplify example app config
jfschwarz Nov 19, 2024
b9fe26b
fix: prep more layouts for smaller side panel (#212)
frontendphil Nov 20, 2024
847f4f6
fix: update RPC redirect rules when new networks are detected (#213)
frontendphil Nov 20, 2024
8b6edb7
chore: remove cyclic dependencies (#215)
frontendphil Nov 21, 2024
a2a1315
fix: only manually reconnect after failure (#214)
frontendphil Nov 21, 2024
18aba04
add madge check (#216)
frontendphil Nov 21, 2024
f398122
chore: updates more styles and reduce number of button types (#217)
frontendphil Nov 22, 2024
688b624
fix: stop redirecting rpc requests when panel closes or simulation fi…
frontendphil Nov 22, 2024
41eec8a
fix: remove style that overrides stuff
frontendphil Nov 22, 2024
9244a4c
chore: harmonize alerts (#219)
frontendphil Nov 25, 2024
e0942da
chore: adjust code after rebase
frontendphil Nov 26, 2024
d5484e6
chore: format code
frontendphil Nov 26, 2024
1519ccb
chore: update dictionary
frontendphil Nov 26, 2024
690ef15
fix: wallet connect (#221)
frontendphil Nov 26, 2024
a32e24a
fix: disconnect wallet connect when wallet disconnects (#222)
frontendphil Nov 26, 2024
87e0a82
chore: move fork provider (#223)
frontendphil Nov 26, 2024
72c1717
fix: always show piloted safe label (#224)
frontendphil Nov 26, 2024
9f1271d
chore: rework modals (#225)
frontendphil Nov 26, 2024
42c4682
update developer docs (#226)
frontendphil Nov 27, 2024
cad24a0
chore: remove legacy colors (#227)
frontendphil Nov 27, 2024
3b3aa7f
feat: dark mode (#228)
frontendphil Nov 27, 2024
2f65c12
chore: breadcrumbs (#229)
frontendphil Nov 27, 2024
79c42d2
create page component (#230)
frontendphil Nov 27, 2024
a66b1fb
chore: migrate toasts (#233)
frontendphil Nov 28, 2024
65520e0
fix: wallet connect error handling (#234)
frontendphil Nov 28, 2024
525b07d
chore: coverage report (#235)
frontendphil Nov 29, 2024
4f076fb
inputs have same height
frontendphil Nov 29, 2024
e3be22a
chore: harmonize inputs (#236)
frontendphil Nov 29, 2024
ebe6e59
chore: fix input description layout
frontendphil Nov 29, 2024
716af32
fix: max width for toasts
frontendphil Nov 29, 2024
3dde212
make sure transaction layout does not break on longer contract names
frontendphil Nov 29, 2024
ffe86b6
fix: update RPC rules when fork is ready (#237)
frontendphil Nov 29, 2024
b1481cf
fix: improve layout for delegate calls
frontendphil Nov 29, 2024
26da135
chore: monitor style and logo update (#238)
frontendphil Dec 2, 2024
cd2f5d5
chore: clear chrome mock listeners after each test (#240)
frontendphil Dec 3, 2024
3fe148c
chore: remove sessions global variable (#241)
frontendphil Dec 3, 2024
538007b
chore: names and docs (#239)
jfschwarz Dec 3, 2024
a803ccf
chore: enable rpc debug logging when tracking requests
frontendphil Dec 3, 2024
8b7eeb3
chore: move badge update and simplify event creation (#242)
frontendphil Dec 4, 2024
52fad56
check for and remove cycles from backend scripts (#243)
frontendphil Dec 4, 2024
6aa943b
chore: update logo again (#244)
frontendphil Dec 4, 2024
a864bfb
add e2e --ui script
jfschwarz Dec 4, 2024
d09c39a
fix: small transaction glitches (#245)
frontendphil Dec 4, 2024
b3dcfc0
chore: remove zodiac os logo for now (#246)
frontendphil Dec 4, 2024
d1a7381
use small buttons for transaction controls
frontendphil Dec 4, 2024
d61011c
chore: save some space (#247)
frontendphil Dec 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
52 changes: 42 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,51 @@
name: CI

on: [push]
on:
pull_request:
push:
branches:
- main

jobs:
tests:
static_checks:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./extension
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
node-version: 21
cache: "yarn"
cache-dependency-path: "**/yarn.lock"
- run: yarn install --immutable
working-directory: ./extension
version: 9
- uses: actions/setup-node@v4
with:
node-version: latest
cache: "pnpm"
cache-dependency-path: "**/pnpm-lock.yaml"
- run: pnpm install --prefer-offline
- name: Run static checks
run: yarn run check
run: pnpm check
unit_tests:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./extension
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: latest
cache: "pnpm"
cache-dependency-path: "**/pnpm-lock.yaml"
- run: pnpm install --prefer-offline
- run: pnpm test:unit
- name: 'Report Coverage'
# Set if: always() to also generate the report if tests are failing
# Only works if you set `reportOnFailure: true` in your vite config as specified above
if: always()
uses: davelosert/vitest-coverage-report-action@v2
with:
working-directory: extension
37 changes: 0 additions & 37 deletions .github/workflows/e2e.yml

This file was deleted.

43 changes: 43 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Playwright Tests
on:
deployment_status:
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
if: github.event.deployment_status.state == 'success'
defaults:
run:
working-directory: ./extension
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: latest
cache: "pnpm"
cache-dependency-path: "**/pnpm-lock.yaml"
- name: Install dependencies
run: pnpm install --prefer-offline

- name: Build
run: pnpm build

- name: Install Playwright Browsers
run: pnpm playwright install --with-deps chromium

- name: Run Playwright tests
run: xvfb-run pnpm playwright test
env:
PLAYWRIGHT_TEST_BASE_URL: ${{ github.event.deployment_status.target_url }}
VERCEL_PROTECTION_BYPASS: ${{ secrets.VERCEL_PROTECTION_BYPASS }}
PW_CHROMIUM_ATTACH_TO_OTHER: 1

- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30
94 changes: 8 additions & 86 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,101 +7,23 @@ Chrome extension to simulate Dapp interactions and record transactions. [Availab

## Contribute

### Run in development
### Overview

Build a development bundle of the extension in watch mode:
The [extension](./extension/) folder hosts the code of the browser extension.
The included [README](./extension/README.md) documents the most important concepts.

```
To run a development version of the extension from a branch:

```bash
cd extension
yarn dev
```

The build output is written to public/build.
The `dev` script will watch for changes and automatically rebuild.

To enable the extension in Chrome, follow these steps:

1. Open the Extension Management page by navigating to [chrome://extensions](chrome://extensions).
2. Enable **Developer Mode** by clicking the toggle switch at the top right of the page.
3. Click the **Load unpacked** button and select the `zodiac-pilot/public` directory.

### Package for production

```
yarn build
```

## How it works

The extension consists of three different interacting pieces:

- **extension app:** This is the main app rendering the iframe. The entrypoint to the app is [launch.ts](extension/src/launch.ts) which is injected into pages running under the [Zodiac Pilot host](#zodiac-pilot-host) via a [content script](https://developer.chrome.com/docs/extensions/mv3/content_scripts/).
- **background script:** A [service worker script](https://developer.chrome.com/docs/extensions/mv3/intro/mv3-overview/#service-workers) that allows to hook into different Chrome events and APIs: [src/background.ts](extension/src/background.ts)
- **injected script:** Whenever we load any page in the the extension app iframe, we inject [src/inject.ts](extension/src/inject.ts) into the page so that this script runs in the context of that page. The injection happens via the content script at [src/contentScript.ts](extension/src/contentScript.ts).

The different scripts communicate exclusively via message passing. Extension page and background script use `chrome.runtime.sendMessage` while extension page and injected script talk via `window.postMessage`.

### Zodiac Pilot host

Originally, we started out building the Pilot as an extension page, which are hosted under `chrome-extension://<EXTENSION_ID>`. However extension pages are subject to some restrictions that make implementing certain integrations difficult, most notably:

- All extensions are sandboxed from each other, meaning that the MetaMask injected provider would not be available to an extension page.
- Extension pages have no access to Indexed DB, which is a dependency of Ganache. We might consider implementing a local forking mechanism using Ganache as an alternative to the existing Tenderly integration.

That's why the extension is now running under an external host, https://pilot.gnosisguild.org.

### Open Dapps in iframe

For allowing arbitrary pages to be loaded in our iframe we drop `X-Frame-Options` and `Content-Security-Policy` HTTP response headers for any requests originating from tabs showing our extension.

As we don't want to generally lift cross origin restrictions, we dynamically adjust the condition under which the [declarativeNetRequest](https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/) rule applies.
In our background script, we track tabs running our extension and will apply the header removal only for requests originating from any of these tabs.

### Syncing iframe location

The problem: When the user navigates the Dapp, the address bar of the Zodiac Pilot should update accordingly.
The browser back button should function as usual and when reloading the extension page the iframe should continue showing the original page.
Since browsers block access to foreign origin iframes we need to leverage Chrome extension super powers to detect navigation events in the iframe.

The solution: We listen to `chrome.tabs.onUpdated` in the background script and notify the content script about it via a message, which relays the message to the extension app.
This relaying is necessary because a background script can not directly talk to an externally hosted app.
For retrieving the new iframe location, we then post a message to the injected script in the iframe window, which will send us the response in another message.

### Inject EIP-1193 provider

When the simulator iframe opens any page, we inject the build/inject.js script as a node into the DOM of the Dapp.

The injected script then runs in the context of the Dapp and injects an [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) compatible API at `window.ethereum`.
The injected provider forwards all `request` calls to the parent extension page via `window.postMessage` where they are recorded and executed in a fork of the connected network.

We also subscribe to messages sent via the [safe-apps-sdk](https://github.com/safe-global/safe-apps-sdk).
This enables instant and smart-account optimized connections to Safe-compatible apps.

### Simulating transaction in a fork

When the provider we inject into the Dapp iframe receives a transaction request, we record it and simulate the transaction in a fork of the target network, impersonating the Safe.
That way the app can continue communicating with the fork network, so that a whole session of multiple transactions can be recorded before anything is signed and submitted to the real chain.

Tenderly provides rich debugging capabilities, which help in understanding the exact effects of each recorded transaction before actually signing anything.
Fresh forks are created via Tenderly's Simulation API and each fork will have its own JSON RPC URL.

### Reroute JSON-RPC fetch requests

Apps commonly make read-only JSON-RPC requests to providers such as Infura or Alchemy rather than going through the EIP-1193 provider injected by the wallet.
Once the network has been forked for simulating recorded transaction such requests should reflect the state of the fork as well.

This first requires detecting which of the JSON-RPC endpoints used by an app actually serve the forked network.
The `webRequest` extension API allows inspecting the body of each outgoing request.
If a requests looks like a JSON-RPC request we probe the target endpoint for `requestChainId`.

Once the network is forked we update `declarativeNetRequest` xhr redirection rules for endpoints identified as serving the forked network.
All of this is implemented as part of the [background service worker](src/background.ts).

### Submitting transactions

A batch of recorded transaction can finally be submitted as a multi-send transaction.
Zodiac Pilot can be configured to submit transactions directly to the Safe if the Pilot account is an owner or delegate, or to route the transaction through Zodiac mods.
This is implemented in [WrappingProvider](src/providers/WrappingProvider.ts).
It currently supports the [Roles](https://github.com/gnosisguild/zodiac-modifier-roles) and [Delay](https://github.com/gnosisguild/zodiac-modifier-delay) mods.

### Overview of providers

![Diagram giving an overview of providers](./docs/providers-diagram.png)
5 changes: 3 additions & 2 deletions connect/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
This is a minimal web app running under https://connect.pilot.gnosisguild.org to allow connecting to the user's wallet extension.
This is an empty web app running under https://connect.pilot.gnosisguild.org to allow connecting to the user's wallet extension.

It communicates with the Pilot extension side panel through `window.postMessage`.
It's sole purpose is having a host for connecting to the wallet.
Since extensions don't have access to injected wallets, Pilot will load this empty site in an iframe injecting a script to use it as a bridge to the wallet.
Loading
Loading