A comprehensive adapter system for managing treasury contracts through Safe multisig wallets, with support for meta-transactions to preserve caller identity.
The AdapterManager contract enables Safe multisig wallets to efficiently manage multiple treasury contracts through a unified interface. It combines three specialized adapters into a single contract and implements a meta-transaction pattern to preserve the original caller's identity.
Managing multiple treasury contracts with a Safe multisig wallet creates operational bottlenecks:
- β Each treasury requires separate role permissions
- β Every permission change needs meeting the Safe's signature threshold
- β Managing permissions across multiple treasuries is exponentially complex
- β Each treasury update requires a full Safe transaction with multiple signatures
AdapterManager solves this by:
β
Consolidating permissions - Configure Safe permission once for the AdapterManager
β
Eliminating repetitive signatures - Manage all treasury interactions through one contract
β
Standardized interface - Consistent API for all treasury operations
β
Meta-transaction support - Preserves original caller identity for access control
β
Quick treasury additions - Add new treasuries without Safe permission changes
- AllOrNothingAdapter - Cancel, pause, unpause operations
- KeepWhatsRaisedAdapter - Crowdfunding treasury management (13 functions)
- PaymentTreasuryAdapter - Payment processing operations (9 functions)
- Preserves Safe multisig identity when calling treasury contracts
- Treasury contracts can verify the actual caller (not just the adapter)
- Enables proper access control and audit trails
- ~200-300 gas overhead per transaction
- Simple admin-based access control
- Zero-address validation on all functions
- Custom error handling for gas efficiency
- Non-upgradeable design for simplicity
- Generic
executeCall()for any contract interaction - Support for complex data types (structs, arrays)
- Overloaded function support
- Batch operations
βββββββββββββββββββ
β Safe Multisig β (Admin)
ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β AdapterManager β
β ββββββββββββββββββββββββββββββββ β
β β KeepWhatsRaisedAdapter β β
β β AllOrNothingAdapter β β
β β PaymentTreasuryAdapter β β
β β BaseAdminAdapter β β
β ββββββββββββββββββββββββββββββββ β
ββββββββββ¬βββββββββββββββββββββββββββββ
β (with meta-transaction)
βΌ
βββββββββββββββββββ
β Treasury β
β Contracts β
βββββββββββββββββββ
- Node.js >=18.0
- npm package manager
# Clone the repository
git clone https://github.com/ccprotocol/safe-multisig-helper-contracts.git
cd safe-multisig-helper-contracts
# Install dependencies
npm install
# Compile contracts
npm run compile# 1. Install dependencies
npm install1. npx hardhat vars set PRIVATE_KEY
2. npx hardhat vars set SAFE_ADMINFor more : configuration-variables
# Run all tests (52 tests)
npm test
# Run with gas reporting
npm run test:gas
# Run with coverage
npm run test:coverage# Deploy to Alfajores testnet
npm run deploy:alfajores
# Deploy to Celo mainnet
npm run deploy:celo
# Deploy with custom Safe multisig as admin
npx hardhat ignition deploy ignition/modules/deploy.ts \
--network alfajores \
--parameters '{"DeployAdapterManager":{"adminAddress":"0xYourSafeAddress"}}'| Document | Description |
|---|---|
| docs/DEPLOYMENT.md | Comprehensive deployment guide with examples, verification, and troubleshooting |
| docs/META_TRANSACTIONS.md | Complete guide to the meta-transaction pattern implementation |
| Document | Description |
|---|---|
| ignition/README.md | Hardhat Ignition deployment guide and quick reference |
| test/README.md | Test suite documentation and usage |
aonCancelTreasury(address treasury, bytes32 message)
aonPauseTreasury(address treasury, bytes32 message)
aonUnpauseTreasury(address treasury, bytes32 message)setPaymentGatewayFee(address treasury, bytes32 pledgeId, uint256 fee)
approveWithdrawal(address treasury)
configureTreasury(address treasury, ...)
updateDeadline(address treasury, uint256 deadline)
updateGoalAmount(address treasury, uint256 goalAmount)
setFeeAndPledge(address treasury, ...)
withdraw(address treasury, uint256 amount)
claimTip(address treasury)
claimFund(address treasury)
kwrCancelTreasury(address treasury, bytes32 message)
kwrPauseTreasury(address treasury, bytes32 message)
kwrUnpauseTreasury(address treasury, bytes32 message)createPayment(address treasury, ...)
cancelPayment(address treasury, bytes32 paymentId)
confirmPayment(address treasury, bytes32 paymentId)
confirmPaymentBatch(address treasury, bytes32[] paymentIds)
claimRefund(address treasury, bytes32 paymentId)
claimRefund(address treasury, bytes32 paymentId, address refundAddress)
ptCancelTreasury(address treasury, bytes32 message)
ptPauseTreasury(address treasury, bytes32 message)
ptUnpauseTreasury(address treasury, bytes32 message)changeAdmin(address _newAdmin)
executeCall(address target, bytes calldata data) returns (bool, bytes)All adapter functions append the caller's address to the calldata, allowing treasury contracts to extract and verify the original Safe multisig address:
// In AdapterManager
bytes memory dataWithSender = abi.encodePacked(data, msg.sender);
treasury.call(dataWithSender);
// In Treasury Contract
function _msgSender() internal view returns (address) {
if (msg.data.length >= 20) {
assembly {
sender := shr(96, calldataload(sub(calldatasize(), 20)))
}
} else {
return msg.sender;
}
}See docs/META_TRANSACTIONS.md for complete implementation details.
The project includes comprehensive test coverage:
- β 52 tests passing
- β AdapterManager tests - Deployment, access control, inheritance
- β Meta-transaction tests - Sender extraction, complex scenarios
- β Adapter tests - All functions for each adapter type
- β Mock contracts - Treasury implementations for testing
Run tests:
# Testnet
npm run deploy:alfajores
# Mainnet
npm run deploy:celoAfter deployment, verify on Celoscan:
npx hardhat verify --network alfajores <CONTRACT_ADDRESS> "<ADMIN_ADDRESS>"- Save the deployed contract address
- Verify the contract on Celoscan
- Test admin functions
- Transfer admin to Safe multisig if needed
- Document for multisig-permission-kit
See docs/DEPLOYMENT.md for detailed deployment instructions.
safe-multisig-helper-contracts/
βββ contracts/
β βββ AdapterManager.sol # Main contract
β βββ base/
β β βββ BaseAdminAdapter.sol # Base admin functionality
β βββ AllOrNothingAdapter.sol # AoN treasury adapter
β βββ KeepWhatsRaisedAdapter.sol # KWR treasury adapter
β βββ PaymentTreasuryAdapter.sol # Payment treasury adapter
β βββ interfaces/ # Treasury interfaces
β βββ mocks/ # Mock contracts for testing
βββ test/
β βββ AdapterManager.test.ts # Main contract tests
β βββ MetaTransaction.test.ts # Meta-transaction tests
β βββ AllOrNothingAdapter.test.ts # AoN adapter tests
β βββ KeepWhatsRaisedAdapter.test.ts # KWR adapter tests
β βββ PaymentTreasuryAdapter.test.ts # Payment adapter tests
β βββ README.md # Test documentation
βββ ignition/
β βββ modules/
β β βββ deploy.ts # Deployment module
β βββ parameters.json # Deployment parameters
β
βββ docs/
β βββ DEPLOYMENT.md # Deployment documentation
β βββ META_TRANSACTIONS.md # Meta-transaction guide
βββ hardhat.config.ts # Hardhat configuration
βββ package.json # Dependencies and scripts
Save the contract address for multisig-permission-kit