Eternal Safe is a decentralized fork of Safe{Wallet}, forked at v1.26.2. Funded by the Safe Grants Program.
- The latest released version is always accessible at https://eternalsafe.eth. If your browser doesn't support ENS, you can use alternatives below with different privacy trade-offs:
- https://eternalsafe.eth.limo - centralized ENS resolution.
- https://eternalsafe-eth.ipns.inbrowser.link - this fetches and verifies client-side the IPFS content.
- https://eternalsafe.earthfast.app - EarthFast (an IPFS alternative) hosts a mirror.
- For the IPFS CID or pinned ENS subdomain, please check the latest release.
- The latest commit on the
eternalsafebranch is always accessible at https://eternalsafe.vercel.app.
- No analytics/tracking
- No backend services needed, only an RPC URL
- Easily runs on IPFS or locally
- And more: full list of changes
You can view the diff from the original Safe{Wallet} here: https://github.com/eternalsafe/wallet/compare/eternalsafe..safe-global:safe-wallet-monorepo:v1.26.2.
Note: This diff is viewed backwards, i.e. additions in this diff are actually lines which are removed in Eternal Safe, and vice versa. Seems to be a bug in GitHub.
Eternal Safe relies completely on the provided RPC URL. It is very important to provide a stable and performant RPC node. Typically, public RPC URLs are not sufficient, and it is recommended to run against a private RPC URL or your own node directly.
You can add custom networks to Eternal Safe by including network parameters in the URL. Here's an example for adding Base Sepolia as a testnet:
https://eternalsafe.eth.limo?chainId=84532&chain=Base%20Sepolia&shortName=base-sepolia&rpc=https%3A%2F%2Fsepolia.base.org¤cy=ETH&symbol=ETH&expAddr=https%3A%2F%2Fsepolia.basescan.org%2Faddress%2F%7B%7Baddress%7D%7D&expTx=https%3A%2F%2Fsepolia.basescan.org%2Ftx%2F%7B%7Bhash%7D%7D&l2=true&testnet=true
Required URL parameters:
chainId: The chain ID of the networkchain: The name of the network (e.g. 'Base Sepolia')shortName: The short name of the network (e.g. 'base-sepolia')rpc: The RPC URL (must be URL-encoded)currency: The name of the native currencysymbol: The symbol of the native currency
Optional URL parameters:
logo: URL to the currency logo image (URL-encoded)expAddr: Block explorer URL template for addresses (URL-encoded)expTx: Block explorer URL template for transactions (URL-encoded)l2: Whether the network is a Layer 2 network (boolean, defaults to false)testnet: Whether the network is a testnet (boolean, defaults to false)
Note: For explorer URLs, use {{address}} and {{txHash}} as placeholders that will be replaced with actual values.
Contributions, be it a bug report or a pull request, are very welcome. Please check our contribution guidelines beforehand.
Create a .env file with environment variables. You can use the .env.example file as a reference.
Here's the list of all the environment variables:
| Env variable | Description |
|---|---|
NEXT_PUBLIC_IS_PRODUCTION |
Set to true to build a minified production app |
NEXT_PUBLIC_SAFE_VERSION |
The latest version of the Safe contract, defaults to 1.4.1 |
NEXT_PUBLIC_WC_PROJECT_ID |
WalletConnect v2 project ID |
If you don't provide some of the variables, the corresponding features will be disabled in the UI.
WalletConnect API key resolution order:
- User-provided key saved in app settings
NEXT_PUBLIC_WC_PROJECT_IDfrom.env- Empty (WalletConnect disabled until a key is provided)
Install the dependencies:
yarnRun the development server:
yarn startOpen http://localhost:3000 with your browser to see the app.
The transaction decoder uses a local selector database in the browser. It does not depend on a remote decoding API in the normal flow.
public/signatures/export_chunk_*: Pre-generated, compressed selector chunks served as static assets.src/utils/hash-lookup.ts: Generated lookup helper that maps a 4-byte selector (0x12345678) to the correct chunk file.grab_split_db.sh: Maintenance script used to rebuild selector chunks and regeneratesrc/utils/hash-lookup.ts.
- The app extracts the first 4 bytes from calldata.
src/utils/hash-lookup.tschooses the matching chunk by hash range.- The client fetches only that chunk from
/signatures/.... - The chunk is decompressed client-side and searched for matching function signatures.
- If no local match exists, raw calldata is shown.
This keeps decoding local and avoids downloading the full signature dataset up front.
Use the script when you want to refresh the local selector dataset:
./grab_split_db.shThe script:
- Downloads signatures from the 4byte API.
- Normalizes/sorts/deduplicates entries.
- Splits the dataset into chunk files.
- Compresses chunks.
- Regenerates
src/utils/hash-lookup.tswith updated hash ranges.
Required CLI tools include: curl, sort, split, awk, zstd, and node.
ESLint:
yarn lint --fix
Prettier:
yarn prettier
Unit tests:
yarn test --watch
To create a new component from a template:
yarn cmp MyNewComponent
This app is built using the following frameworks:
- Safe Core SDK (Protocol Kit)
- Next.js
- React
- Redux
- MUI
- ethers.js
- web3-onboard