Tally Ho is a community owned and operated Web3 wallet, built as a browser extension.
Today's Web3 landscape is dominated by a single wallet and a single infrastructure provider, both owned by a single conglomerate. These facts undermine the censorship resistance of Ethereum today... and they're also against Web3's spirit of community ownership.
We can do better.
Tally Ho will be
- Fairly launched βοΈ
- Sustainably aligned with users π€²
- Wholly owned by the community πͺ
Try this.
$ nvm use
$ nvm install
$ npm install -g yarn # if you don't have yarn globally installed
$ yarn install # install all dependencies; rerun with --ignore-scripts if
# scrypt node-gyp failures prevent the install from completing
$ yarn start # start a continuous webpack build that will auto-update with changes
Once the build is running, you can install the extension in your browser of choice:
- Firefox instructions
- Chrome, Brave, Edge, and Opera instructions
- Note that these instructions are for Chrome, but substituting
brave://extensions
oredge://extensions
oropera://extensions
forchrome://extensions
depending on browser should get you to the same buttons.
- Note that these instructions are for Chrome, but substituting
Extension bundles for each browser are in dist/<browser>
.
By default, the yarn start
command rebuilds the extension for each browser on
save. You can target a particular browser by specifying it in the command, e.g.
to only rebuild the Firefox extension on change:
# On change, rebuild the firefox extension but not others.
$ yarn start --config-name firefox
# On change, rebuild the firefox and brave extensions but not others.
$ yarn start --config-name firefox --config-name brave
In some Linux distributions such as Ubuntu 20.04, you need to explicitly
tell npm where your python3
executable is located before running the above
commands successfully:
$ npm config set python /usr/bin/python3
The extension is built as two packages, background
and ui
. background
contains the bulk of the extension's background script,
while ui
contains the code powering extension popups.
These are separate packages in order to emphasize the difference in attack
surface and clearly separate the threat models of each. In particular, ui
is considered untrusted code, while background
is considered trusted code.
Only background
should interact with key material regularly, while ui
should
only interact with key material via a carefully maintained API.
The background
package is also intended to minimize external dependencies
where possible, reducing the surface exposed to a supply chain attack.
Dependencies are generally version-pinned, and yarn
is used to ensure the
integrity of builds.
Builds are designed to be run from the top level of the repository.
If youβre on macOS, install Homebrew and run scripts/macos-setup.sh
. Note
that if you donβt have Homebrew or youβre not on macOS, the below information
details what youβll need. The script additionally sets up pre-commit hooks.
$ ./scripts/macos-setup.sh
If you need to create or update a validation function then:
- You need to write the schema in the
.ts
file to have correct typing. - Add the new schema with the validator function name to the
generate-validators.ts
file - You need to update the
jtd-validators.d.ts
orjson-validators.d.ts
files with the typing definition - run
yarn run generate:validators
- import it in your code and happy validating :)
This setup is necessary so we don't need to include unsafe-eval
in the CSP policy.
If you can't use the macOS setup script, here is the software you'll need to install:
jq
: Instructionsnvm
: Instructionspre-commit
: Instructions
Before committing code to this repository or a fork/branch that you intend to
submit for inclusion, please make sure you've installed the pre-commit hooks
by running pre-commit install
. The macOS setup script does this for you.
For more detailed description see ./dev-utils/local-chain/README.md
Quick Start:
$ cd dev-utils/local-chain
$ yarn install
$ yarn start
Commits on the Tally Ho repository are all required to be signed. No PR will be merged if it has unsigned commits. See the GitHub documentation on commit signing to get it set up.
This repository uses yarn version
to create new versions. Typical usage:
$ yarn version --patch # bump patch version, e.g. 0.0.5->0.0.6
$ yarn version --minor # bump minor version, e.g. 0.1.5->0.2.0
Major releases generally require more discussion than this automation allows, but can be managed the same way.
Bumping a version in this way will do a few things:
- Ensure the commit is running on the correct branch (
release-<new-version>
) for review. If you are on a different branch, the script attempts to switch to a new branch based on the latest origin/main. Releases should generally only add version bumps to the main branch. - Synchronize the extension manifest version to the updated package version.
- Commit, tag, and push the new version and branch.
Once the branch is pushed, you should open a pull request. This will do any further processing, including potentially managing automated submission of the new version to extension directories (as relevant).
$ yarn build # create a production build of the extension
The build script will generate a ZIP file for each browser bundle under the
dist/
directory.
$ yarn lint # lint all sources in all projects
$ yarn lint-fix # auto-fix any auto-fixable lint issues
$ yarn test # run all tests in all projects
Because lint configurations can occasionally evolve in a way that hits many
files in the repository at once and obscures the functional blame readout for
files, this repository has a .git-blame-ignore-revs
file. This file can be
used to run git blame
while skipping over the revisions it lists, as
described in the Pro Git book
reference
and this Moxio blog
post.
To make use of this, you can do one of the following:
- Run
git config --global blame.ignoreRevsFile .git-blame-ignore-revs
to configure git to globally look for such a file. The filename is relatively standard across projects, so this should save time for other projects that use a similar setup. - Run
git config blame.ignoreRevsFile .git-blame-ignore-revs
to configure your local checkout to always ignore these files. - Add
--ignore-revs-file .git-blame-ignore-revs
to yourgit blame
invocation to ignore the file one time.
The GitHub UI does not yet ignore these commits, though there is a community thread requesting the feature. In the meantime, the GitHub blame UI does allow you to zoom to the previous round of changes on a given line, which relieves much of the annoyance; see the GitHub blame docs for more.
Here is a light architecture diagram describing the relationship between services (in the API package) and the interface and browser notifications:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β ____ _ β
β / ___| ___ _ ____ _(_) ___ ___ ___ β
β \___ \ / _ \ '__\ \ / / |/ __/ _ \/ __| ββββββββββββββββββββββΌβββ
β ___) | __/ | \ V /| | (_| __/\__ \ β β β
β |____/ \___|_| \_/ |_|\___\___||___/ β β β βββββββββββββββββββ
β Chain β β βExternal Servicesβ
β - Blocks βββββββββββββ β β β β
β βββββsubscribe (incoming or outgoing tx status)ββββΆ - Transactions β β β β Local node β
β β β β β β β
β β β β β β Alchemy β
β β β β βββββΆ β
β β Indexing β β β β BlockNative β
β β - Accounts β β β β β
β β - ERC-20 balances βββββββββββΌβββ β CoinGecko β
β ββββsubscribe (eg balance changes), get balancesββββΆ - ERC-721 ownership β β β β
β β - Governance proposals β β β β
β β - On-chain prices β β βββββββββββββββββββ
β β β β
β β β β ββββββββββββββββββ
β β Keyring β β β β
β βββββββlist accounts, sign tx, sign messageββββββββΆ - Native βββββββββββββββββββββββΌβββββββΆ Extension β
β β - Remote β β β Storage API β
β ββββββββββββ΄βββββββββββ β β β β
β β β β β ββββββββββββββββββ
β β β β β
β β Wallet API ββββββββ Preferences ββββββββββββββ« β
β β β β β β ββββββββββββββββββ
β β β β β β β β
β ββββββββββββ²βββββββββββ β Notifications β β β β
β β β - Ephemeral β£βββββββββββββΆ IndexedDB β
β β βββββββpull and subscribeββββββββΆ - Application ββββββββ β β β
β β - Security-critical β β β
β subscribe β β ββββββββββββββββββ
β and get β β
β β β β
β β push β
β β β β
βββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΌβββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββ βββββββββββββββββΌββββββββββββββββ
β β β β
β β β β
β Wallet interface β β Browser notifications β
β β β β
β β β β
ββββββββββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββββ
βββββββββββββββββ
β β
β Internal dApp β
β β
βββββββββββββββββ
ββββββββ ββββββββ
β Earn β β Swap β
ββββββββ ββββββββ
Extension content lives directly under the root directory alongside
project-level configuration and utilities, including GitHub-specific
functionality in .github
. Extension content should be minimal, and
largely simply glue together UI and wallet code. Manifest information
is managed in the manifest/
subdirectory as described below.
Here is a light guide to the directory structure:
.github/ # GitHub-specific tooling
package.json # private extension package
webpack.config.js # Webpack build for extension
src/ # extension source files
background.js # entry file for the background extension script; should be
# minimal and call in to @tallyho/tally-wallet
ui.js # entry file for the frontend UI; should be minimal and bind
# the functionality in @tallyho/tally-ui
dist/ # output directory for builds
brave/ # browser-specific
chrome/ # build
edge/ # directories
firefox/
brave.zip # browser-specific
chrome.zip # production
edge.zip # bundles
firefox.zip
build-utils/ # build-related helpers, used in webpack.config.js
*.js
dev-utils/ # dev-mode helpers for the extension
extension-reload.js # LiveReload support for the extension.
manifest/ # extension manifest data
manifest.json # common manifest data for all browsers
manifest.chrome.json # manifest adjustments for Chrome
manifest.dev.json # manifest adjustments for dev environment
manifest.firefox.dev.json # manifest adjustments for Firefox in dev
background/ # @tallyho/tally-background package with trusted wallet core
package.json
ui/ # @tallyho/tally-ui package
package.json