Safe{Wallet} (Gnosis Safe) Integration
Safe (formerly Gnosis Safe) is de facto standard multisig wallet in EVM ecosystem. Over $100 billion in assets under management, integrated in most large DAOs and corporate treasuries. Essence: smart contract wallet with M-of-N signatures where transaction executes only after required threshold of signatures from owners.
Integration with Safe needed in several scenarios: DAO treasury management, corporate control over smart contracts, multisig for DeFi protocols, custom interface for team asset management.
Safe Architecture
Safe contract is GnosisSafe.sol with modular architecture. Key components:
Owners and Threshold. List of owner addresses and minimum signatures for execution. Changing these parameters itself requires threshold signatures.
Modules. Additional smart contracts executing transactions on behalf of Safe without standard signing process. Used for automation (Zodiac, Gelato), recovery mechanisms, custom flows.
Guards. Contracts called before and after each Safe transaction for additional checks. Implement address whitelists, amount limits, cooldown periods.
Fallback Handler. Handles calls to unknown functions and receive(). Used to support additional standards (ERC-1155, EIP-1271).
Safe Transaction Service and API
Safe supports offline signature collection via Safe Transaction Service — hosted API from Safe team. Flow:
- Proposer (any owner) creates transaction and sends to Transaction Service
- Other owners see pending transaction in interface, check and sign
- After threshold signatures collected — anyone can execute on-chain (paying gas)
import SafeApiKit from '@safe-global/api-kit'
import Safe from '@safe-global/protocol-kit'
const apiKit = new SafeApiKit({
chainId: 1n // Ethereum mainnet
})
// Create pending transaction
const safeTransaction = await safeSdk.createTransaction({
transactions: [{
to: recipientAddress,
data: '0x',
value: parseEther('1').toString()
}]
})
const safeTxHash = await safeSdk.getTransactionHash(safeTransaction)
const senderSignature = await safeSdk.signHash(safeTxHash)
await apiKit.proposeTransaction({
safeAddress,
safeTransactionData: safeTransaction.data,
safeTxHash,
senderAddress,
senderSignature: senderSignature.data
})
For custom frontend: @safe-global/protocol-kit and @safe-global/api-kit — official SDKs. Work in browser and Node.js.
Safe Apps SDK: Embedding dApps
Safe Apps are dApps running inside Safe interface as iframes. Key point: Safe App doesn't send transactions directly, but passes them to Safe for signing via @safe-global/safe-apps-sdk.
import SafeAppsSDK from '@safe-global/safe-apps-sdk'
const sdk = new SafeAppsSDK()
// Instead of normal wallet.sendTransaction
const txs = [{
to: contractAddress,
data: contract.interface.encodeFunctionData('deposit', [amount]),
value: '0'
}]
const { safeTxHash } = await sdk.txs.send({ txs })
If need to embed existing dApp in Safe ecosystem or create custom treasury management app — this is main path.
Zodiac: Modular Extensibility
Zodiac is framework from Gnosis Guild extending Safe via modules. Ready modules:
Reality Module — executes transactions based on on-chain voting results via Kleros or Reality.eth. Safe + Snapshot + Reality Module = DAO treasury without on-chain voting gas.
Delay Module — adds timelock to transactions. Critical for protocols: even if threshold signatures collected, transaction waits N hours before execution. Users can notice and react to malicious changes.
Roles Module — granular access control. Different addresses can call specific functions of specific contracts with specific parameters. Example: "multisig can call only rebalance() on strategy, not withdraw()".
Custom Guards and Modules
If need specific logic — write custom Guard or Module.
Example Guard with daily spending limit:
contract SpendingLimitGuard is BaseGuard {
uint256 public dailyLimit;
uint256 public currentDay;
uint256 public spentToday;
function checkTransaction(
address to,
uint256 value,
bytes memory data,
// ... other parameters
) external override {
if (block.timestamp / 1 days > currentDay) {
currentDay = block.timestamp / 1 days;
spentToday = 0;
}
require(spentToday + value <= dailyLimit, "Daily limit exceeded");
spentToday += value;
}
function checkAfterExecution(bytes32 txHash, bool success) external override {}
}
Guard connected via Safe.setGuard(guardAddress) — transaction itself requires threshold signatures.
Multichain Safe and Safe{Core} AA
Safe deployed on 15+ networks, contract addresses same (deployment via CREATE2 with same salt). Safe address on Ethereum and Arbitrum can be same if deployed with same parameters (owners, threshold, nonce).
Safe{Core} Account Abstraction SDK — new stack integrating Safe with ERC-4337. Safe contract becomes ERC-4337 Account, transactions go through bundler, can use Paymaster for gas payment in ERC-20.
Integration Stack
| Task | Tool |
|---|---|
| SDK for transactions | @safe-global/protocol-kit |
| Pending transactions | @safe-global/api-kit |
| Safe Apps (iframe dApp) | @safe-global/safe-apps-sdk |
| Modules and extensions | Zodiac framework |
| AA integration | @safe-global/safe-core-sdk |
Timeline
Basic integration — UI for creating/signing/executing transactions via Safe Transaction Service, pending transactions list, history: 3-4 weeks.
Advanced integration with custom modules, Guard contracts, Safe Apps, Zodiac: 6-8 weeks + audit of custom contracts.
Safe contracts passed many audits — Safe itself secure. Risks — in custom modules and Guards written for project.







