safe-smart-account: the audited contracts behind Safe multisig wallets
Safe allows secure management of blockchain assets.
At a glance
- What is it?
- The Solidity and TypeScript repository for Safe's Ethereum multisig, with deterministic per-network deployment, an audit trail going back to version 0.0.1, and a main branch that is deliberately ahead of the last release.
- Who is it for?
- This repository is for people who need to deploy or reason about Safe's contract suite, not for people who want a wallet. It ships the contracts, the deployment scripts that put them at known addresses on every network, the tests, and the formal verification configuration, and it carries the longest audit trail in this class of project, with reports for every version from 0.0.1 through 1.5.0.
- Can I use it commercially?
- Yes, with conditions. LGPL-3.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Star history
- safe-fndn/safe-smart-account2,184 ★ · +0
| Repository | 2026-10-08 | 2026-10-23 |
|---|---|---|
| safe-fndn/safe-smart-account | 2.2k | 2.2k |
0 Stars in the last 15 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Two repository names in one project
The repository lives under the safe-fndn organisation, and almost nothing inside it agrees. The README's build badge, its coverage badge, the npm package badge, the documentation links and the release comparison links all point at safe-global. The npm package name is @safe-global/safe-smart-account. The homepage is safe.global. The developer portal link uses the docs.safe.global host.
The release history explains the split. Version 1.5.0, published on 2025-07-03, lists as its first change the rename of the repository and the npm package to safe-smart-account, and it links the changelog under safe-global. An earlier release, v1.4.1-3 from 2024-10-02, still links the deployed addresses through a gnosis/safe-deployments path, because the project has been through at least two organisation names.
So this is a rename caught mid-flight rather than a broken reference. Nothing in the README tells you which organisation is current, and the tree you cloned is under safe-fndn. The practical consequence is small but annoying: links generated from this checkout will point somewhere other than where you are, and if you are looking for a companion repository by following a path from the README, expect the name to have moved again.
Topics are the usual three, ethereum, solidity and wallet, and the recorded primary language is TypeScript, which reflects the tooling rather than the substance. The contracts are Solidity; the TypeScript is the deployment layer, the tests and the Hardhat configuration.
Main is ahead of what is audited and deployed
The README opens with a warning that the branch you are reading contains changes under development, and separately states the current version as v1.5.0 on a specific commit hash. Those two statements are the single most important operational fact in the repository.
The audit list tops out at version 1.5.0. The release list tops out at v1.5.0, published on 2025-07-03. The last push to this repository was on 2026-09-24. That is well over a year of commits sitting on the default branch beyond the last audited, tagged, deployed version, and the README tells you this itself by warning you to use the correct commit if you want the audited version.
The reason this matters more here than in an ordinary library is stated twice in the deployment section. Changing anything inside the contract files, including comments, produces different addresses. So deploying from main does not give you a slightly different build of the same contracts; it gives you contracts at different addresses than every Safe deployment in the world, and any tooling, token allowlist or integration keyed to the canonical addresses will not recognise them.
The recommendation the README makes is the right one and worth following literally: clone, check out the tagged release commit, confirm it matches the audit report you intend to rely on, and deploy from there. The main branch is where the next version is being written, which is useful for reading and a poor choice for deploying.
Deterministic deployment, and the two ways it can go wrong
Deployment is one npm script per network, and the README is unusually clear about the two failure modes that make addresses differ.
npm run deploy-all <network>That expands into a fixed sequence:
npm run build
npx hardhat --network <network> deploy
npx hardhat --network <network> sourcify
npx hardhat --network <network> etherscan-verify
npx hardhat --network <network> local-verifyCompilation, deployment, source publication, explorer verification and then a local check comparing the compiled artifacts against what is actually on chain. That last step is the one most projects skip, and it is the step that catches a mismatched compiler or a proxy pointing somewhere unexpected.
The first way to get different addresses is the commit, described above. The second is the compiler. Deployment uses Solidity 0.7.6 by default, while the environment sample offers a version override with 0.8.19 given as the example value, and there is a separate variable for optimizer settings. The README states plainly that addresses vary if the contract code changes or a different Solidity version is used. If you are reproducing a known Safe address, both the commit and the compiler settings are part of the input.
The third factor is the network configuration itself. Arbitrary EVM chains are reached through a node URL variable and the custom network entry, and the README claims addresses should then be the same on all networks. The qualifier that follows is the important part: that holds only while the code and compiler stay fixed.
Replay protection breaks the default deployment path
Networks that require EIP-155 replay protection are the documented exception, and the README dedicates a section to them because the failure is confusing when you hit it.
The default process deploys through a deterministic deployment proxy using a presigned transaction without replay protection, which such networks reject. Safe does not use that proxy. It uses its own deterministic deployment proxy, published as a separate package, and the README instructs you to install that package as a development dependency before deploying so you are not using a stale copy:
npm i --save-dev @safe-global/safe-singleton-factoryThe consequence, stated in the README, is that this route produces different addresses than Hardhat's default deterministic deployment would. So the address you read from documentation for a given network may assume one route while your build takes the other. If you are comparing your deployment against a known Safe address, which deterministic proxy was used is a third thing to verify alongside the commit and the compiler.
Supporting networks is a separate repository entirely. Deployed addresses for every chain live in safe-deployments, and adding a new network means following the deploy steps here and then opening a pull request there. That split means this repository has no list of live addresses, which is correct design for something that changes, and inconvenient if you were expecting to read them locally.
A test suite split across four configurations
The test command is not one run. The package script chains four suites, which tells you most of what the maintainers consider distinct enough to break:
npm run build
npm run testThose expand to a plain Hardhat network suite, a suite forced onto chain id 1 and filtered to tests tagged for L1, a run against the SafeL2 contract variant, and a run with the secp256r1 precompile enabled filtered to tests tagged for it. The separate L2 variant exists because the L2 contract differs from the L1 one, chiefly in how it emits events, so passing the L1 suite tells you nothing about the L2 build.
The secp256r1 configuration is worth understanding as well, because it exists because signature validation has more than one path. An environment variable turns on the precompile so the tests can cover the case where signatures are verified by a contract rather than by the ecrecover precompile.
Beyond tests there is a gas report toggle, a codesize script, a benchmark script pointing at a benchmark directory, coverage, and linting split into Solidity and TypeScript halves. The ERC-4337 compatibility test is deliberately excluded from the default run: it needs a live bundler and a live node, four environment variables for the bundler URL, node URL, singleton address and Safe factory address, plus a mnemonic whose derived executor account has been pre-funded with native token to cover module deployment and the test operation. That is a deliberate boundary rather than a flaky test, and running it means paying for real deployments.
The repository also carries a certora directory for formal verification, alongside the audit reports in docs/.
Audits for every version, and an explicit absence of warranty
The audit history is the strongest signal in this repository and it is unusual to see it laid out this completely. Every version has a report: 0.0.1 by Alexey Akhunov, 1.0.0 by Runtime Verification, 1.1.1 and 1.2.0 by G0 Group, 1.3.0 by G0 Group with Certora and Nethermind, 1.4.0 and 1.4.1 by Ackee Blockchain, and 1.5.0 by Certora and Ackee.
Two things to read carefully in that list. The firm changes over time, which is normal, and Runtime Verification's involvement on 1.0.0 is a different kind of work from a manual audit, since formal verification proves properties rather than finding instances. And none of these reports covers the current main branch, which is the practical limit on how much the audit history can tell you about the code in front of you.
The liability statement is short and unambiguous: the contracts are without any warranty, without even the implied warranty of merchantability or fitness for a particular purpose. Read alongside a version list that stops at 1.5.0, it sets a clear expectation that you verify the version you deploy.
The licensing is LGPL-3.0 for the smart contracts, matching the package metadata. For a contract suite intended to be deployed as infrastructure and then interacted with by other software, the practical question is whether your use triggers the copyleft obligations, which is a question for your own counsel rather than something the repository settles. Bug bounty information is pointed at the developer portal rather than documented here.
Editorial conclusion
This repository is for people who need to deploy or reason about Safe's contract suite, not for people who want a wallet. It ships the contracts, the deployment scripts that put them at known addresses on every network, the tests, and the formal verification configuration, and it carries the longest audit trail in this class of project, with reports for every version from 0.0.1 through 1.5.0. Two boundaries are worth respecting. The main branch is not what is deployed: the README names v1.5.0 on a specific commit as the version the Safe team uses, and addresses change if you deploy from a different commit, so pin before you deploy anything. And a large amount of work landed after that release, so the gap between main and the audited version is real rather than theoretical. Read the version 1.5.0 audit report, install the matching singleton factory as the README instructs, and only then run deploy-all against a network you can afford to get wrong.
Frequently asked questions
How do I deploy the Safe contracts to a network?
Check out the tagged release commit first, install the matching singleton factory package as a development dependency, then run npm run deploy-all with the network name. That expands into compile, deploy, sourcify, explorer verification and a local check of the on-chain code against the build artifacts. Deploying from the default branch instead produces different contract addresses.
Why do my Safe contract addresses differ from the published ones?
Two documented causes. Any change inside the contract files, comments included, produces different addresses, so the commit you deploy from matters. The compiler version matters too: deployment defaults to Solidity 0.7.6 and the environment sample shows an override, and the README states addresses vary with a different Solidity version. A third factor is which deterministic deployment proxy was used, since the Safe singleton factory differs from Hardhat's default.
Which version of safe-smart-account has been audited?
The audit reports in docs/ cover versions 0.0.1 through 1.5.0, with 1.5.0 audited by Certora and Ackee and 1.4.0 and 1.4.1 by Ackee Blockchain. No report covers the default branch, which the README warns contains changes under development and which has received commits since the 1.5.0 release in July 2025.
Do I need a running bundler to run the safe-smart-account tests?
Not for the default suite, which chains four Hardhat runs covering the standard network, an L1 configuration, the SafeL2 variant and a secp256r1 precompile configuration. Only the optional ERC-4337 compatibility test needs a live bundler and node, along with four ERC4337_TEST environment variables and a pre-funded mnemonic, which is why it is kept out of the default command.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/safe-fndn-safe-smart-account)Star history chart for your README
[](https://hysenlabs.com/projects/safe-fndn-safe-smart-account)Was this useful?