This repository contains the code for the Voyage core web extension. For details, refer to the RFC.
npm i
npm run start
- TypeScript
- React 17
- Webpack 5
- Manifest version 3
- Mantine
In the project directory, you can run:
Runs the app in development mode. All compiled assets will be in build
. To preview the extension, load it into Chrome.
Note that the extension, including background and content scripts, are automatically hot reloaded thanks to @voyage-finance/webpack-ext-loader, our fork of SimplifyJob/webpack-ext-reloader.
Launches the test runner in the interactive watch mode.
See the section about running tests for more information.
Builds the app for production to the build
folder.
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.\
There are env.*.example
files that you can use for your environment
For dev, you can switch on debugging mode. Also, by defining these variables, extension will bypass getTorusKey request for any email.
VOYAGE_DEBUG=true
DEBUG_LOCALHOST_PRIVATE_KEY= // First priority for generating wallet
DEBUG_GOERLI_MNEMONIC= // Second priority for generating wallet
Voyage Extension has a few major components:
- UI -- React code that powers the popup and tab views. Communicates with background using
PortStream
+ObjectMultiplex
- Background -- houses
VoyageController
, the central API for both UI andcontentscript
- ContentScript -- enables the extension to manipulate the DOM. Communicates with backgound using
PortStream
+ObjectMultiplex
- This is the main entrypoint for business logic and persistent state.
- This is the right place to set up handlers for
sendMessage
listeners. VoyageController
has privileged access to private keys. Never allow access to its methods from unknown sources (third party extensions and websites).- It exposes its API via client/server in
src/rpc/virtual
, an RPC abstraction over Chrome's message passing. This is howcontentscript
andui
callVoyageController
- Calling methods via
RPCClient
may seem like magic, but only serializable data can be passed. This means returning aPromise
is not going to work!
- Calling methods via
- This responds to all RPC method calls coming from
contentscript
andui
viaBaseProvider
. - It only gets called for methods like
eth_accounts
, which needs to return the Vault address (for example). - More methods will be handled here, such as
eth_sign
, etc.
- Reactive store based on
mobx
. It sends state updates to the UI viasendUpdate
onVoyageController
. - On the UI side, this state is managed using
Redux
, because it is far easier to update the entire state tree using it. - Note that all state that needs to be exposed should be returned from each sub-store's
get state()
getter. These must then be called in theget state()
of the rootControllerStore
. This ensures that the UI will be automatically updated when any sub-store is updated.
- The UI is a very typical React/Redux application that you have seen dozens of times before.
- The only store right now is
core
. It holds allVoyageController
state and is updated each time something changes inVoyageController
. State that is local to the UI can be handled, as far as possible, within component functions with hooks. - If you need to add more app-wide state, don't add it to
core
, as that is isolated and reserved forVoyageController
state. - Like the Web UI, it runs on
mantine
. We should probably extract the custom components into a common shared library at some stage. - The only interesting bits are in
src/ui/web3/init.ts
-- which is responsible for establishing a connection to thebackground
script viaPortStream
. - Additionally, because the global object is a bit wonky in extensions, we use
globalThis
instead ofwindow
orglobal
. provider
andcontroller
are always available in the UI context, globally.