Safe{Wallet} Plugin Development

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Safe{Wallet} Plugin Development
Medium
~3-5 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1218
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    853
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1047
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Safe{Wallet} Plugin Development

Safe (formerly Gnosis Safe) is the de-facto standard for multisig custody in Web3. $100B+ TVL, thousands of DAOs and protocols. But Safe's basic functionality is just multisig. Plugins (formerly Modules) extend it into a fully programmable treasury: automatic payments, role-based access, DeFi integrations, spending limits without separate multisig voting.

Safe Extensions Architecture in Safe v1.4+

Safe{Core} Protocol is a modular system on top of Safe Account. Since version 1.4, Safe moved to a new architecture with three types of extensions:

Type What it does
Plugin Executes transactions on behalf of Safe without multisig
Hook Validates transactions before/after execution
Function Handler Handles calls to Safe through fallback

Plugin is the most powerful type. It can call execTransactionFromModule() on the Safe contract, bypassing the signature threshold. This is why plugin installation requires full multisig approval.

interface ISafeProtocolPlugin {
    function name() external view returns (string memory);
    function version() external view returns (string memory);
    function metadataHash() external view returns (bytes32);
}

A plugin is registered in SafeProtocolRegistry — a whitelist of approved extensions. A custom plugin for mainnet Safe either needs to pass an audit for inclusion in the official registry, or be used through a custom Manager.

Example: Spending Limit Plugin

The most common use case is restricted access for operational expenses. Instead of voting 3/5 on every payment, the team installs a plugin that allows a specific address to spend up to N USDC per day without multisig.

contract SpendingLimitPlugin is ISafeProtocolPlugin {
    struct AllowanceConfig {
        uint128 dailyLimit;
        uint128 spent;
        uint64 resetTimestamp;
    }
    
    // safe => token => delegate => config
    mapping(address => mapping(address => mapping(address => AllowanceConfig))) public allowances;
    
    function executeSpend(
        ISafeProtocolManager manager,
        ISafe safe,
        address token,
        address to,
        uint128 amount
    ) external {
        AllowanceConfig storage config = allowances[address(safe)][token][msg.sender];
        
        // reset daily limit
        if (block.timestamp >= config.resetTimestamp + 1 days) {
            config.spent = 0;
            config.resetTimestamp = uint64(block.timestamp);
        }
        
        require(config.spent + amount <= config.dailyLimit, "Daily limit exceeded");
        config.spent += amount;
        
        // Transfer through Safe without multisig
        bytes memory data = abi.encodeCall(IERC20.transfer, (to, amount));
        SafeTransaction memory tx = SafeTransaction({
            to: token,
            value: 0,
            data: data,
            operation: Enum.Operation.Call
        });
        
        (, bytes memory returnData) = manager.executeTransaction(safe, tx);
    }
}

The official allowances module from Safe already implements similar logic — for standard spending limits, it's better to use it. A custom plugin is needed when non-standard logic is required: multi-token limits, role-based models, DeFi integration.

Hook: Transaction Validation Before Execution

A Hook allows you to add additional checks to any Safe transaction:

contract TransactionGuardHook is ISafeProtocolHook {
    mapping(address => bool) public blockedAddresses;
    
    function preCheck(
        ISafe safe,
        SafeTransaction calldata tx,
        uint8 executionType,
        bytes calldata executionMeta
    ) external view returns (bytes memory preCheckData) {
        // Prevent transactions to blacklist addresses
        require(!blockedAddresses[tx.to], "Blocked address");
        
        // Prevent calls to dangerous functions
        if (tx.data.length >= 4) {
            bytes4 selector = bytes4(tx.data[:4]);
            require(!blockedSelectors[selector], "Blocked function");
        }
        
        return abi.encode(block.timestamp);
    }
    
    function postCheck(ISafe safe, bool success, bytes calldata preCheckData) external {
        // post-execution logic
    }
}

Typical Hook use cases: compliance (blocking transactions to sanctioned addresses via Chainalysis oracle), budget control (preventing budget overruns), whitelist (only pre-approved recipient addresses).

Safe{Core} Protocol Manager

In the new architecture, a Plugin doesn't call Safe directly — only through SafeProtocolManager. The Manager is a mediator that verifies the plugin is enabled for the specific Safe and that the registry approves it.

// Enable plugin through multisig Safe transaction
function enablePlugin(address plugin, uint8 permissions) external authorized {
    ISafeProtocolManager(MANAGER).enablePlugin(plugin, permissions);
}

permissions is a bitmask: EXECUTE_DELEGATECALL (0x01), EXECUTE_CALL (0x02). DelegateCall should be used carefully — a plugin with delegatecall rights executes in Safe's context and can modify its storage.

Testing Safe Plugins

Tests through Foundry with mainnet fork and real Safe:

contract SpendingLimitTest is Test {
    ISafe safe;
    SpendingLimitPlugin plugin;
    
    function setUp() public {
        // Fork mainnet
        vm.createFork(MAINNET_RPC);
        
        // Deploy Safe through SafeProxyFactory
        safe = ISafe(safeFactory.createProxyWithNonce(
            SAFE_SINGLETON, 
            initData, 
            block.timestamp
        ));
        
        // Deploy and enable plugin
        plugin = new SpendingLimitPlugin();
        vm.prank(address(safe));
        manager.enablePlugin(address(plugin), 2);
    }
    
    function test_SpendWithinLimit() public {
        vm.prank(delegate);
        plugin.executeSpend(manager, safe, USDC, recipient, 100e6);
        
        assertEq(IERC20(USDC).balanceOf(recipient), 100e6);
    }
    
    function testFail_ExceedDailyLimit() public {
        vm.prank(delegate);
        plugin.executeSpend(manager, safe, USDC, recipient, 10000e6); // > daily limit
    }
}

Development Process

Analytics (0.5-1 day). Determine extension type (Plugin/Hook/FunctionHandler), required permissions, integrations (DeFi protocols, oracles, other modules).

Development (2-3 days). Plugin contract, Foundry tests with mainnet fork. Safe registry integration. If custom Manager is needed — additional day.

Audit and review (0.5-1 day). Special attention to reentrancy through execTransactionFromModule, correctness of permission checks, impossibility of bypassing multisig through plugin under undesirable conditions.

Frontend integration (1 day). Safe Apps SDK for displaying plugin interface directly in Safe{Wallet} UI.

Total: 3-5 days for a typical plugin. Complex multi-module systems with DeFi integrations — up to 2 weeks.