Protocol Modules
Protocol modules are the bridge between NMT's permission system and external DeFi protocols. Each module knows how to interact with one specific protocol.
Module Architecture
All modules inherit from BaseModule.sol, which provides:
- Permission checking (queries PermissionsManager)
- Safe call utilities (executes transactions through the user's Safe)
- Common safety checks
BaseModule (shared logic)
|
+-- UniswapV3Module
+-- UniswapV2Module
+-- AaveModule
+-- MorphoModule
+-- YearnModule
+-- AerodromeModule
+-- RelayModule
External modules (not in this repo):
+-- CowModule (MEV-protected swaps via PRESIGN)
+-- KrystalModule (automated LP vaults, ERC-4626)
Module Details
UniswapV3Module
Protocol: Uniswap V3 (concentrated liquidity) Operations: Mint position, burn position, collect fees, increase/decrease liquidity
This is the most complex module because Uniswap V3 positions are NFTs with specific price ranges (tick ranges). The module handles:
- Creating new concentrated liquidity positions with specific tick bounds
- Collecting earned trading fees
- Removing liquidity and burning the position NFT
UniswapV2Module
Protocol: Uniswap V2 (basic AMM) Operations: Swap tokens, add liquidity, remove liquidity
Simpler than V3 — Uniswap V2 uses a constant-product formula without tick ranges.
AaveModule
Protocol: Aave V3 (lending/borrowing) Operations: Supply collateral, borrow assets, repay debt, withdraw
Interacts with Aave's Pool contract through the PoolAddressesProvider. Supports:
- Supplying tokens as collateral to earn interest
- Borrowing against supplied collateral
- Repaying borrowed amounts
- Withdrawing supplied collateral
MorphoModule
Protocol: Morpho (optimized lending) Operations: Deposit into MetaMorpho vaults, withdraw
Morpho vaults are ERC-4626 compliant, meaning the module uses standard deposit() and withdraw() interfaces.
YearnModule
Protocol: Yearn Finance (yield vaults) Operations: Deposit into Yearn vaults, withdraw
Like Morpho, Yearn uses the ERC-4626 vault standard. The module handles approval and deposit/withdrawal flows.
AerodromeModule
Protocol: Aerodrome (Base chain DEX) Operations: Swap, add liquidity, remove liquidity
Aerodrome is the primary DEX on Base chain. The module supports both standard AMM pools and Slipstream (concentrated liquidity) pools.
RelayModule
Protocol: Gelato Relay Operations: Sponsored/gasless transactions
Enables transactions where gas fees are paid by the platform (via Gelato's relay service) rather than the user. Used for subscription-based automated executions.
CowModule (External)
Protocol: Cow Protocol (MEV-protected swaps) Operations: Approve tokens, sign/unsign orders, wrap/unwrap native tokens
The CowModule is deployed externally — it is not part of the NMT contracts repo. It integrates with Cow Protocol's GPv2Settlement contract using the PRESIGN signing scheme. Since Safes cannot produce ECDSA signatures like EOAs, PRESIGN authorizes orders purely by the Safe executing the call.
Key functions:
executeCoWApproval()— approve tokens for the Cow relayerexecuteCoWSignOrder()— register a PRESIGN order on GPv2Settlement viasetPreSignature()executeCoWUnsignOrder()— cancel a pending orderexecuteCoWWrapNative()/executeCoWUnwrapNative()— wrap/unwrap ETH for Cow swaps
Safe-only: Cow Protocol is only available in Safe mode because it requires the PRESIGN scheme.
| Chain | CowModule Address |
|---|---|
| Ethereum | 0x365485a1Bd944fa155aC2CCfDbC3D56232af3Cc0 |
| Base | 0x34f0d479edAA0AB36B90C755010dE7d7B9571629 |
| Arbitrum | 0x7F1B5929856633Bf59A493f1Ed5FB46a83d2E486 |
KrystalModule (External)
Protocol: Krystal (automated liquidity vaults) Operations: Deposit into vaults, withdraw from vaults, approve tokens
The KrystalModule is deployed externally. It integrates with Krystal's automated LP vault protocol, which manages concentrated liquidity positions on Uniswap V3. Vaults follow the ERC-4626 standard.
Key functions:
executeKrystalDeposit()— deposit tokens into a Krystal vaultexecuteKrystalWithdraw()— redeem shares from a Krystal vaultexecuteKrystalApproval()— approve tokens for the vault
Note: EOA withdrawals from Krystal vaults are not yet implemented — currently Safe-mode only for withdrawals.
| Chain | KrystalModule Address |
|---|---|
| Ethereum | 0x11844b2bde4f0f4745DffF52CCBF5f4D808B49a1 |
| Base | 0xde229a4F93031624e0F41193aFfF399e1a2DE3D0 |
| Arbitrum | 0x872720ecf3519a10F813e1A476d3b53058cc74fd |
Key External Addresses
Each module interacts with specific protocol contracts. These addresses differ by chain:
| Module | Key Contract | Base Address |
|---|---|---|
| UniswapV3 | NonfungiblePositionManager | 0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1 |
| UniswapV2 | Router | 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D |
| Aave | PoolAddressesProvider | 0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb |
| Aerodrome | Router | 0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43 |
Testing
Tests are in smart-wallets/test/ and use Hardhat + Chai:
| Test Suite | Status |
|---|---|
| PermissionsManager | Covered |
| UniswapV3Module | Covered |
| UniswapV2Module | Covered |
| AaveModule | Covered |
| YearnModule | Covered |
| MorphoModule | Not yet covered |
| AerodromeModule | Not yet covered |
| RelayModule | Not yet covered |
Contract Location
smart-wallets/contracts/modules/