Skip to content

Instantly share code, notes, and snippets.

@doncesarts
Created March 14, 2026 06:59
Show Gist options
  • Select an option

  • Save doncesarts/1e169ad530f6225db3f52eb388c8b851 to your computer and use it in GitHub Desktop.

Select an option

Save doncesarts/1e169ad530f6225db3f52eb388c8b851 to your computer and use it in GitHub Desktop.
Gnosis Safe Module minimal Example
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import { Enum } from "@safe-global/safe-smart-account/contracts/interfaces/Enum.sol";
import {
IModuleManager
} from "@safe-global/safe-smart-account/contracts/interfaces/IModuleManager.sol";
/**
* @title StipendModule
* @notice Minimal example module for periodic token transfers via Safe wallet.
* @dev WARNING: This contract is NOT production ready. It lacks security checks, upgradeability, and robust error handling.
* Use only for demonstration or testing purposes.
*/
contract StipendModule {
address public immutable safeWallet;
address public immutable token;
address public immutable recipient;
uint256 public lastExecuted;
uint256 public immutable amount;
uint256 public constant interval = 4 weeks;
error MultiSendNotConfigured();
error ZeroAddress();
error ZeroAmount();
error PrematureExecution(uint256 currentTime, uint256 nextAllowedTime);
constructor(address _safeWallet, address _token, address _recipient, uint256 _amount) {
if (_safeWallet == address(0)) revert ZeroAddress();
if (_token == address(0)) revert ZeroAddress();
if (_recipient == address(0)) revert ZeroAddress();
if (_amount == 0) revert ZeroAmount();
safeWallet = _safeWallet;
token = _token;
recipient = _recipient;
amount = _amount;
lastExecuted = block.timestamp;
}
/**
* @notice Execute a call via the Safe contract
* @param to Destination address to call
* @param data Data payload of the transaction
* @return success bool for success
*/
function _execCallFromModule(address to, bytes memory data)
internal
virtual
returns (bool success)
{
IModuleManager safe = IModuleManager(safeWallet);
success = safe.execTransactionFromModule({
to: to, value: 0, data: data, operation: Enum.Operation.Call
});
require(success, "!success");
return success;
}
function stipend() external {
if (block.timestamp < lastExecuted + interval) {
revert PrematureExecution(block.timestamp, lastExecuted + interval);
}
bytes memory data = abi.encodeWithSignature("transfer(address,uint256)", recipient, amount);
lastExecuted = block.timestamp;
_execCallFromModule(token, data);
}
/*//////////////////////////////////////////////////////////////////////////
METADATA
//////////////////////////////////////////////////////////////////////////*/
/**
* Returns the name of the module
*
* @return name of the module
*/
function name() external pure virtual returns (string memory) {
return "StipendModule";
}
/**
* Returns the version of the module
*
* @return version of the module
*/
function version() external pure virtual returns (string memory) {
return "0.0.0";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment