npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mihailo-maksa/safe-guards

v0.1.0

Published

A library of multi-tenant transaction guards for Safe multisig wallets — enforces custom security policies via Safe's checkTransaction hooks.

Downloads

48

Readme

Safe Guards

A collection of transaction guards for Safe multisig wallets.

Safe Guards provides reusable, tested guard contracts that hook into Safe's checkTransaction flow to enforce custom security policies before transactions execute. For more on Safe's guard mechanism, see the Safe documentation.

Guards

| Guard | Description | |-------|-------------| | SignerOnlyGuard | Only Safe owners can call execTransaction. Prevents non-owners from executing pre-signed transactions. | | AllowedTargetsGuard | Whitelist target addresses the Safe can interact with. | | DelegateCallGuard | Block or whitelist delegatecall operations (blocks all by default). | | SpendingLimitGuard | Enforce a maximum net native balance decrease per time period. | | FunctionWhitelistGuard | Whitelist specific function selectors per target contract. |

Installation

npm (recommended)

npm install @mihailo-maksa/safe-guards

Import contracts:

import {SpendingLimitGuard} from "@mihailo-maksa/safe-guards/contracts/SpendingLimitGuard.sol";
import {AllowedTargetsGuard} from "@mihailo-maksa/safe-guards/contracts/AllowedTargetsGuard.sol";

Foundry (forge install)

forge install mihailo-maksa/safe-guards

Foundry's auto-remapping maps safe-guards/ to lib/safe-guards/contracts/, so import without the contracts/ prefix:

import {SpendingLimitGuard} from "safe-guards/SpendingLimitGuard.sol";

You must also install the Safe dependency (used by the guards internally):

npm install @safe-global/safe-smart-account

And add this remapping to your remappings.txt:

@safe-global/safe-smart-account/=node_modules/@safe-global/safe-smart-account/

Usage

SignerOnlyGuard

Deploy the guard (stateless — one deployment serves many Safes):

SignerOnlyGuard guard = new SignerOnlyGuard();

Then set it on your Safe via setGuard(address(guard)) through a Safe transaction.

AllowedTargetsGuard

AllowedTargetsGuard guard = new AllowedTargetsGuard();
// After setting guard on Safe, whitelist targets via Safe transactions:
// guard.addTarget(trustedContract);

DelegateCallGuard

Blocks all delegatecalls by default. Optionally whitelist specific targets:

DelegateCallGuard guard = new DelegateCallGuard();
// After setting guard on Safe, optionally allow delegatecall targets:
// guard.allowDelegateCallTarget(trustedImplementation);

SpendingLimitGuard

SpendingLimitGuard guard = new SpendingLimitGuard();
// After setting guard on Safe, configure limits via Safe transaction:
// guard.setLimit(10 ether, 1 days);  // Max 10 ETH net decrease per day

How it works: Uses a balance-snapshot pattern — measures preBalance - postBalance across checkTransaction and checkAfterExecution to track the actual net native balance decrease. This correctly handles gas refund payments and failed inner calls.

Note: Only tracks native balance changes, not ERC-20 token transfers.

FunctionWhitelistGuard

FunctionWhitelistGuard guard = new FunctionWhitelistGuard();
// After setting guard on Safe, whitelist functions via Safe transactions:
// guard.setFunction(tokenAddress, IERC20.transfer.selector, true);
// guard.setBareTransfer(recipient, true);  // Allow plain ETH transfers

Architecture

All guards extend BaseGuard, which provides a default no-op checkAfterExecution implementation. Guards use msg.sender (the Safe calling the guard) rather than storing the Safe address, making them multi-tenant — a single deployment can serve multiple Safes.

Admin functions (adding/removing whitelist entries, configuring limits) are called by the Safe itself via Safe transactions. The guard keys all storage by msg.sender, isolating each Safe's configuration.

Security Considerations

  • Not yet audited — a formal audit is planned for the future. Review the code carefully before deploying to production.
  • Module execution is out of scope — these guards only protect execTransaction. Safe has a separate module-guard interface (IModuleGuard) for execTransactionFromModule that this package does not implement. If your Safe has enabled modules, configure Safe's module guard separately.
  • SignerOnlyGuard scope — SignerOnlyGuard only restricts who can execute Safe transactions; it does not restrict targets, function selectors, value, or delegatecall operations. If you need owner-only execution plus additional policy checks, use a custom composite guard.
  • Guard removal and self-calls — when using AllowedTargetsGuard, the Safe's own address must be whitelisted to allow any self-calls (including guard removal via setGuard). Note that whitelisting the Safe's address permits all self-calls, not just guard management. When using FunctionWhitelistGuard, the setGuard(address) selector must be whitelisted for the Safe's own address to allow guard removal. Configure these whitelists before setting the guard to avoid lockout.
  • Delegatecall — AllowedTargetsGuard, FunctionWhitelistGuard, and SpendingLimitGuard reject delegatecall operations by default. DelegateCallGuard provides fine-grained delegatecall control with an optional whitelist.
  • SpendingLimitGuard only tracks native balance changes — it does not track ERC-20 token transfers or other value movements. Failed transactions with native ETH gas refunds (gasPrice > 0, gasToken == address(0)) still consume allowance because the Safe's native balance actually decreases.
  • DelegateCallGuard whitelist is critical — whitelisted delegatecall targets can modify the Safe's storage arbitrarily. Only whitelist thoroughly audited or otherwise trusted contracts.
  • Multi-tenant design — all guards use msg.sender keying, so a single deployment serves multiple Safes with isolated configuration. However, the guard contract itself is a shared dependency — if it has a bug, all Safes using it are affected.
  • Compiler version — contracts are tested with solc 0.8.28. The ^0.8.20 pragma allows consumers to use any compatible version.
  • Contributions and security reviews from the community are welcome — please open an issue or pull request if you find a vulnerability.

Chain Compatibility

These guards work on any EVM-compatible chain where Safe is deployed, including:

  • Ethereum Mainnet
  • Arbitrum
  • Optimism
  • Polygon
  • Base
  • Gnosis Chain

See the Safe deployments registry for a full list of supported networks.

Development

Prerequisites

Setup

git clone https://github.com/mihailo-maksa/safe-guards.git
cd safe-guards
npm install

Build

forge build

Test

forge test -vvv

Coverage

forge coverage

Format

forge fmt --check

Contributing

Contributions are welcome! Please open an issue or pull request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/my-feature)
  3. Run tests (forge test -vvv)
  4. Ensure formatting passes (forge fmt --check)
  5. Open a pull request

License

MIT