Skip to content

Latest commit

 

History

History
925 lines (696 loc) · 26.2 KB

File metadata and controls

925 lines (696 loc) · 26.2 KB

Smart Modules - Comprehensive Documentation

Table of Contents

  1. System Overview
  2. Architecture
  3. Core Components
  4. Component Details
  5. Integration & Workflows
  6. Security Model
  7. Use Cases
  8. Technical Implementation
  9. Testing Strategy

System Overview

This is a modular DeFi (Decentralized Finance) system built on Ethereum that provides:

  1. Automated Market Maker (AMM) Liquidity Pool - Enables token swaps with liquidity provision
  2. EIP-712 Meta-Transaction Support - Allows gasless transactions via off-chain signatures
  3. Fee Management System - Upgradeable fee calculation and management
  4. Multi-Signature Vault - Secure multi-party governance for fund management
  5. Role-Based Access Control - Granular permission system for different operations

Key Principles

  • Modularity: Each component is independent and can be upgraded/replaced
  • Security: Multiple layers of access control and validation
  • Upgradeability: Critical components use proxy patterns for future improvements
  • Gas Efficiency: Optimized for on-chain operations
  • Composability: Components work together seamlessly

Architecture

High-Level Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Smart Modules System                      │
├─────────────────────────────────────────────────────────────┤
│                                                               │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐ │
│  │   Liquidity  │    │   EIP712Swap  │    │  FeeManager  │ │
│  │     Pool     │◄───┤   (Relayer)  │◄───┤  (Upgradeable)│ │
│  └──────────────┘    └──────────────┘    └──────────────┘ │
│         │                     │                    │        │
│         └─────────────────────┼────────────────────┘        │
│                               │                              │
│                    ┌──────────▼──────────┐                   │
│                    │   AccessManager     │                   │
│                    │  (Role Management)  │                   │
│                    └──────────┬──────────┘                   │
│                               │                              │
│                    ┌──────────▼──────────┐                   │
│                    │   VaultMultisig     │                   │
│                    │  (Multi-Sig Vault)  │                   │
│                    └─────────────────────┘                   │
│                                                               │
└─────────────────────────────────────────────────────────────┘

Component Relationships

  1. LiquidityPool - Core AMM functionality

    • Uses FeeManager for fee calculations
    • Grants permissions to EIP712Swap for meta-transactions
    • Managed by admins via AccessManager roles
  2. EIP712Swap - Meta-transaction relayer

    • Verifies off-chain signatures
    • Executes swaps on behalf of users
    • Requires ALLOWED_EIP712_SWAP_ROLE from pool
  3. FeeManager - Upgradeable fee system

    • Calculates fees based on swap parameters
    • Can be upgraded via UUPS proxy pattern
    • Managed by admins
  4. AccessManager - Centralized role management

    • Manages all role assignments
    • Used by VaultMultisig for multisig admin permissions
  5. VaultMultisig - Multi-signature vault

    • Manages funds with quorum-based approvals
    • Can execute arbitrary contract calls
    • Uses AccessManager for admin permissions

Core Components

1. LiquidityPool

Purpose: Automated Market Maker (AMM) for token swaps

Key Features:

  • Constant product formula (x * y = k) for price discovery
  • Admin-controlled liquidity management
  • Role-based swap authorization
  • Support for different token decimals

Core Functions:

  • addLiquidity() - Admin-only liquidity provision
  • removeLiquidity() - Admin-only liquidity withdrawal
  • swap() - Execute token swaps (admin or authorized EIP712 contract)
  • getPrice() - Query current exchange rate
  • getReserves() - View current pool reserves

Access Control:

  • ADMIN_ROLE: Can add/remove liquidity
  • ALLOWED_EIP712_SWAP_ROLE: Can execute swaps (granted to EIP712Swap contract)

2. EIP712Swap

Purpose: Enable gasless transactions via EIP-712 typed data signatures

Key Features:

  • EIP-712 compliant signature verification
  • Nonce management to prevent replay attacks
  • Deadline enforcement for time-bound operations
  • Signature verification before execution

Core Functions:

  • verify() - Verify swap request signature
  • executeSwap() - Execute swap with valid signature
  • getNonce() - Get current nonce for an address
  • getDomainSeparator() - Get EIP-712 domain separator

Security Mechanisms:

  • Nonce increment prevents replay attacks
  • Deadline check prevents stale transactions
  • Signature verification ensures request authenticity

3. FeeManager

Purpose: Calculate and manage swap fees (upgradeable)

Key Features:

  • UUPS (Universal Upgradeable Proxy Standard) upgradeable
  • Basis points fee calculation (1 bp = 0.01%)
  • Fee calculated on output amount
  • Admin-controlled fee updates

Core Functions:

  • initialize() - Initialize with initial fee
  • setFee() - Update fee (admin only)
  • getFee() - Calculate fee for swap parameters
  • _authorizeUpgrade() - Control upgrade authorization

Fee Calculation:

// 1. Calculate output amount using AMM formula
amountOut = (amountIn * reserveOut) / (reserveIn + amountIn)

// 2. Calculate fee as percentage of output
fee = (amountOut * feeBasisPoints) / 10000

4. AccessManager

Purpose: Centralized role-based access control

Key Features:

  • Manages three distinct roles:
    • ADMIN_ROLE: General admin permissions
    • MULTISIG_ADMIN_ROLE: Vault multisig administration
    • ALLOWED_EIP712_SWAP_ROLE: EIP712 swap permissions
  • Role hierarchy with DEFAULT_ADMIN_ROLE as root

Core Functions:

  • addAdmin() / removeAdmin() - Manage admin roles
  • addMultisigAdmin() / removeMultisigAdmin() - Manage multisig admins
  • addEIP712Swapper() / removeEIP712Swapper() - Manage EIP712 swappers
  • isAdmin() / isMultisigAdmin() / isEIP712Swapper() - Check role membership

5. VaultMultisig

Purpose: Multi-signature vault for secure fund management

Key Features:

  • Quorum-based transaction approval
  • Support for ETH transfers and arbitrary contract calls
  • Configurable signers and quorum
  • Operation tracking and history

Core Functions:

  • initiateTransfer() - Propose ETH transfer
  • approveTransfer() - Approve transfer proposal
  • executeTransfer() - Execute approved transfer
  • initiateOperation() - Propose contract call
  • approveOperation() - Approve operation proposal
  • executeOperation() - Execute approved operation
  • updateSigners() - Update multisig signers (multisig admin only)
  • updateQuorum() - Update required quorum (multisig admin only)

Workflow:

  1. Signer initiates transfer/operation
  2. Other signers approve until quorum reached
  3. Any signer executes when quorum met
  4. Operation marked as executed (prevents replay)

6. Roles Library

Purpose: Centralized role constant definitions

Key Features:

  • Prevents role hash collisions
  • Ensures consistent role usage across contracts
  • Three defined roles with unique hashes

Roles:

  • ADMIN_ROLE: keccak256("ADMIN_ROLE")
  • MULTISIG_ADMIN_ROLE: keccak256("MULTISIG_ADMIN_ROLE")
  • ALLOWED_EIP712_SWAP_ROLE: keccak256("ALLOWED_EIP712_SWAP_ROLE")

Component Details

LiquidityPool - Deep Dive

AMM Formula

The pool uses a simplified constant product formula:

amountOut = (amountIn * reserveOut) / (reserveIn + amountIn)

This formula ensures:

  • Price impact increases with trade size
  • Pool always maintains liquidity
  • No need for external price oracles

Swap Process

  1. Validation:

    • Check token pair is valid (token0 or token1)
    • Verify sender has sufficient allowance
    • Ensure sufficient liquidity exists
  2. Calculation:

    • Calculate output amount using AMM formula
    • Calculate fee using FeeManager
    • Deduct fee from output amount
  3. Execution:

    • Transfer input tokens from user to pool
    • Transfer output tokens (minus fee) to user
    • Update reserves
  4. Events:

    • Emit Swap event with all swap details

Price Calculation

price = (reserveOut * 1e18) / reserveIn

Returns price normalized to 18 decimals for consistent comparison.

EIP712Swap - Deep Dive

EIP-712 Standard

EIP-712 enables signing structured data (not just raw hashes), providing:

  • Better UX (wallets show human-readable data)
  • Type safety
  • Domain separation (prevents cross-chain replay)

Signature Structure

struct SwapRequest {
    address pool;
    address sender;
    address tokenIn;
    address tokenOut;
    uint256 amountIn;
    uint256 minAmountOut;
    uint256 nonce;
    uint256 deadline;
}

Signature Verification Process

  1. Create Type Hash:

    TYPEHASH = keccak256("SwapRequest(address pool,address sender,...)")
  2. Create Struct Hash:

    structHash = keccak256(abi.encode(TYPEHASH, pool, sender, ...))
  3. Create Domain Separator:

    domainSeparator = keccak256(
        abi.encode(
            keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
            keccak256("EIP712Swap"),
            keccak256("1"),
            chainId,
            contractAddress
        )
    )
  4. Create Final Hash:

    digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash))
  5. Recover Signer:

    signer = digest.recover(signature)

Nonce Management

  • Each address has a unique nonce counter
  • Nonce increments after successful swap execution
  • Prevents replay attacks and ensures order

FeeManager - Deep Dive

Upgradeability Pattern

Uses UUPS (Universal Upgradeable Proxy Standard):

  • Implementation contract holds logic
  • Proxy contract holds state
  • Upgrade function in implementation (not proxy)
  • More gas-efficient than Transparent Proxy

Fee Calculation Logic

// Step 1: Calculate output using AMM formula
uint256 amountOut = (amountIn * reserveOut) / (reserveIn + amountIn);

// Step 2: Calculate fee as percentage of output
uint256 fee = (amountOut * feeBasisPoints) / FEE_DENOMINATOR; // FEE_DENOMINATOR = 10000

Example:

  • Input: 100 tokens
  • Reserves: 1000 in, 2000 out
  • Fee: 250 basis points (2.5%)
  • Output: (100 * 2000) / (1000 + 100) = 181.81 tokens
  • Fee: (181.81 * 250) / 10000 = 4.55 tokens
  • Final output: 181.81 - 4.55 = 177.26 tokens

Upgrade Authorization

Only DEFAULT_ADMIN_ROLE can authorize upgrades, ensuring:

  • Controlled upgrade process
  • No unauthorized logic changes
  • Audit trail via events

VaultMultisig - Deep Dive

Quorum System

  • Quorum: Minimum number of approvals required
  • Signers: List of authorized addresses
  • Validation: Quorum ≤ Signers.length

Transfer Workflow

  1. Initiation (initiateTransfer):

    • Signer proposes transfer
    • Automatically counts as 1 approval
    • Creates Transfer struct with ID
  2. Approval (approveTransfer):

    • Other signers approve
    • Approval count increments
    • Prevents duplicate approvals
  3. Execution (executeTransfer):

    • Any signer can execute when quorum reached
    • Validates balance sufficiency
    • Executes ETH transfer
    • Marks as executed (prevents replay)

Operation System

Similar to transfers but for arbitrary contract calls:

  • initiateOperation: Propose contract call with encoded data
  • approveOperation: Approve operation
  • executeOperation: Execute when quorum reached

Use Cases:

  • Call LiquidityPool functions
  • Interact with other DeFi protocols
  • Update contract parameters

Security Features

  1. Replay Prevention: Executed operations cannot be re-executed
  2. Balance Checks: Validates sufficient balance before execution
  3. Quorum Validation: Ensures minimum approvals before execution
  4. Signer Verification: Only authorized signers can participate
  5. Admin Controls: Only multisig admins can update signers/quorum

Integration & Workflows

Workflow 1: Standard Token Swap

User → LiquidityPool.swap()
  ├─ Check authorization (admin or EIP712 contract)
  ├─ Validate token pair
  ├─ Check allowance
  ├─ Calculate output (AMM formula)
  ├─ Calculate fee (FeeManager.getFee())
  ├─ Transfer tokens
  └─ Update reserves

Workflow 2: Gasless Swap via EIP-712

1. User (Off-chain):
   ├─ Create SwapRequest struct
   ├─ Sign with EIP-712
   └─ Send signature to relayer

2. Relayer (On-chain):
   ├─ Call EIP712Swap.executeSwap()
   ├─ Verify signature
   ├─ Check nonce & deadline
   ├─ Call LiquidityPool.swap()
   └─ Increment nonce

Workflow 3: Multi-Signature Fund Management

1. Signer 1:
   └─ initiateTransfer(recipient, amount)

2. Signer 2:
   └─ approveTransfer(transferId)

3. Signer 3 (or any signer):
   └─ executeTransfer(transferId)
      └─ ETH transferred to recipient

Workflow 4: Liquidity Management

Admin → LiquidityPool.addLiquidity()
  ├─ Validate token address
  ├─ Check balance
  ├─ Transfer tokens to pool
  └─ Update reserves

Workflow 5: Fee Update

Admin → FeeManager.setFee()
  ├─ Check admin role
  ├─ Update fee value
  └─ Future swaps use new fee

Security Model

Access Control Layers

  1. Role-Based Access Control (RBAC):

    • OpenZeppelin AccessControl implementation
    • Hierarchical role structure
    • Role admin relationships
  2. Function-Level Modifiers:

    • onlyRole() - OpenZeppelin modifier
    • onlyAdminOrEIP712Swap() - Custom modifier
    • onlyMultisigSigner() - VaultMultisig modifier
  3. Contract-Level Authorization:

    • EIP712Swap contract has special role
    • Can execute swaps on behalf of users
    • Signature verification ensures user consent

Security Mechanisms

1. Reentrancy Protection

  • No external calls before state updates in critical functions
  • Checks-Effects-Interactions pattern followed

2. Integer Overflow Protection

  • Solidity 0.8.30 built-in overflow checks
  • Safe math operations

3. Signature Verification

  • EIP-712 standard prevents signature manipulation
  • Nonce prevents replay attacks
  • Deadline prevents stale transactions

4. Input Validation

  • Token address validation
  • Amount validation (non-zero, sufficient balance)
  • Quorum validation (≤ signers, > 0)

5. Upgrade Safety

  • UUPS pattern with admin-only upgrade authorization
  • Implementation contract can be audited before upgrade
  • Upgrade function protected by role

Known Security Considerations

  1. Centralization Risks:

    • Admin roles have significant power
    • Multisig reduces but doesn't eliminate risk
    • Consider time-locks for critical operations
  2. Front-Running:

    • Public mempool allows front-running
    • Consider commit-reveal schemes for large trades
  3. Liquidity Risks:

    • Low liquidity can cause high slippage
    • Admin-controlled liquidity adds centralization
  4. Signature Replay:

    • EIP-712 domain separation prevents cross-chain replay
    • Nonce prevents same-chain replay
    • Deadline prevents stale transactions

Use Cases

1. Decentralized Exchange (DEX)

Scenario: Users want to swap tokens without centralized exchange

Implementation:

  • Deploy LiquidityPool with token pair
  • Admin adds initial liquidity
  • Users swap tokens via swap() or EIP-712

Benefits:

  • No order book needed
  • Automated price discovery
  • Always available liquidity

2. Gasless Trading

Scenario: Users want to trade without paying gas fees

Implementation:

  • User signs swap request off-chain
  • Relayer pays gas and executes
  • Relayer may charge fee or be sponsored

Benefits:

  • Better UX (no gas management)
  • Enables mobile-first DeFi
  • Reduces barrier to entry

3. Treasury Management

Scenario: DAO or organization needs secure fund management

Implementation:

  • Deploy VaultMultisig with DAO signers
  • Set quorum (e.g., 3 of 5)
  • All transfers require quorum approval

Benefits:

  • No single point of failure
  • Transparent approval process
  • Audit trail via events

4. Liquidity Provision

Scenario: Protocol wants to provide liquidity for token pairs

Implementation:

  • Admin adds liquidity to pool
  • Earns fees from swaps
  • Can remove liquidity when needed

Benefits:

  • Passive income from fees
  • Supports token ecosystem
  • Flexible liquidity management

5. Fee Optimization

Scenario: Protocol wants to adjust fees based on market conditions

Implementation:

  • Admin updates FeeManager fee
  • New fee applies to all future swaps
  • Can be upgraded if needed

Benefits:

  • Dynamic fee adjustment
  • Upgradeable without migration
  • Maintains fee revenue

Technical Implementation

Solidity Version

  • Version: 0.8.30
  • Features Used:
    • Built-in overflow/underflow checks
    • Custom errors (gas efficient)
    • Struct packing
    • Library usage

OpenZeppelin Contracts

  1. AccessControl: Role-based permissions
  2. AccessControlUpgradeable: Upgradeable access control
  3. UUPSUpgradeable: Upgradeable proxy pattern
  4. Initializable: Proxy initialization
  5. EIP712: Typed data signing
  6. ECDSA: Signature recovery

Gas Optimization Techniques

  1. Custom Errors: Instead of require strings (saves gas)
  2. Events: Efficient event emission
  3. Struct Packing: Efficient storage layout
  4. Library Functions: Reusable code without deployment overhead
  5. View Functions: No gas cost for read operations

Storage Layout

LiquidityPool

address token0;              // slot 0
uint256 token0Decimals;       // slot 1
address token1;             // slot 2
uint256 token1Decimals;       // slot 3
uint256 reserveToken0;       // slot 4
uint256 reserveToken1;       // slot 5
FeeManager feeManager;       // slot 6
EIP712Swap eip712Swap;        // slot 7

VaultMultisig

uint256 quorum;              // slot 0
uint256 transfersCount;      // slot 1
uint256 operationsCount;     // slot 2
AccessManager accessManager; // slot 3
address[] currentMultiSigSigners; // slot 4 (array length)
mapping(uint256 => Transfer) transfers; // slot 5
mapping(uint256 => Operation) operations; // slot 6
mapping(address => bool) multiSigSigners; // slot 7

Error Handling

Custom errors used throughout for gas efficiency:

error InsufficientTokenBalance();
error InvalidTokenAddress(address _token);
error InvalidTokenPair(address _tokenIn, address _tokenOut);
error InsufficientLiquidity();
error InsufficientOutputAmount(uint256 expected, uint256 actual);
error InsufficientAllowance();
error InvalidSignature();
error ExpiredSwapRequest();
error InvalidNonce();

Event Emission

All state changes emit events for:

  • Off-chain indexing
  • Front-end updates
  • Audit trails
  • Analytics

Key events:

  • LiquidityAdded: When liquidity is added
  • Swap: When swap is executed
  • TransferInitiated/Approved/Executed: Multisig workflow
  • OperationInitiated/Approved/Executed: Multisig operations

Testing Strategy

Test Coverage

The system includes comprehensive tests covering:

  1. Unit Tests: Individual component functionality
  2. Integration Tests: Component interactions
  3. Edge Cases: Boundary conditions and error scenarios
  4. Access Control: Role-based permission testing

Test Files

  1. LiquidityPool.t.sol (12 tests):

    • Liquidity management
    • Swap functionality
    • Access control
    • Error conditions
  2. EIP712Swap.t.sol (3 tests):

    • Signature verification
    • Swap execution
    • Multiple swaps
    • Insufficient liquidity handling
  3. FeeManager.t.sol (9 tests):

    • Fee calculation
    • Fee updates
    • Different scenarios
    • Access control
  4. VaultMultisig.t.sol (27 tests):

    • Transfer workflow
    • Operation workflow
    • Quorum management
    • Signer management
    • Error conditions
  5. AccessManager.t.sol (5 tests):

    • Role management
    • Access control
    • Authorization checks
  6. Roles.t.sol (2 tests):

    • Role constant validation
    • Uniqueness checks

Test Patterns Used

  1. Arrange-Act-Assert: Standard test structure
  2. Fuzz Testing: Random input generation (potential)
  3. Invariant Testing: State consistency checks
  4. Integration Testing: Multi-contract scenarios

Mock Contracts

  • MockERC20: ERC20 token for testing
    • Configurable decimals
    • Mint/burn functions
    • Standard ERC20 interface

Test Utilities

  • Foundry Test Framework: forge-std/Test.sol
  • vm.prank(): Impersonate addresses
  • vm.expectRevert(): Test error conditions
  • vm.expectEmit(): Test event emission
  • vm.deal(): Fund addresses with ETH

Deployment Considerations

Deployment Order

  1. Roles Library: Deploy first (no dependencies)
  2. AccessManager: Deploy with admin
  3. FeeManager Implementation: Deploy implementation contract
  4. FeeManager Proxy: Deploy proxy with initialization
  5. EIP712Swap: Deploy relayer contract
  6. LiquidityPool: Deploy with all dependencies
  7. VaultMultisig: Deploy with signers and AccessManager

Initialization Parameters

FeeManager

  • Initial fee (basis points, e.g., 250 = 2.5%)
  • Admin address

LiquidityPool

  • Token0 address and decimals
  • Token1 address and decimals
  • FeeManager address
  • EIP712Swap address

VaultMultisig

  • Signers array
  • Quorum (must be ≤ signers.length, > 0)
  • AccessManager address

Upgrade Considerations

  1. FeeManager: Can be upgraded via UUPS pattern

    • New implementation must be compatible
    • Storage layout must match
    • Admin must authorize upgrade
  2. Other Contracts: Not upgradeable

    • Consider proxy pattern if upgradeability needed
    • Or deploy new version and migrate

Gas Costs (Estimated)

  • LiquidityPool.addLiquidity(): ~60,000 gas
  • LiquidityPool.swap(): ~150,000-250,000 gas
  • EIP712Swap.executeSwap(): ~200,000-300,000 gas
  • VaultMultisig.initiateTransfer(): ~50,000 gas
  • VaultMultisig.executeTransfer(): ~80,000 gas

Best Practices

For Developers

  1. Always validate inputs: Check addresses, amounts, etc.
  2. Use events: Emit events for all state changes
  3. Handle errors gracefully: Use custom errors
  4. Test thoroughly: Cover edge cases
  5. Document code: Use NatSpec comments

For Administrators

  1. Secure private keys: Use hardware wallets
  2. Use multisig: For critical operations
  3. Monitor events: Track all contract interactions
  4. Test upgrades: On testnet first
  5. Gradual changes: Don't make drastic changes at once

For Users

  1. Check allowances: Before swapping
  2. Verify signatures: When using EIP-712
  3. Check deadlines: Don't use expired signatures
  4. Monitor nonces: Track your nonce for EIP-712 swaps
  5. Understand slippage: Set appropriate minAmountOut

Future Enhancements

Potential Improvements

  1. Liquidity Provider Tokens (LP Tokens):

    • Track liquidity provider shares
    • Enable proportional liquidity removal
    • Reward liquidity providers
  2. Time-Weighted Average Price (TWAP):

    • Oracle-free price feeds
    • More accurate pricing
    • Reduced manipulation risk
  3. Flash Loans:

    • Uncollateralized loans within transaction
    • Enable arbitrage opportunities
    • Require repayment in same transaction
  4. Multi-Hop Swaps:

    • Route through multiple pools
    • Better prices for indirect pairs
    • Automatic routing
  5. Governance Token:

    • Decentralized fee management
    • Community-driven decisions
    • Staking mechanisms
  6. MEV Protection:

    • Commit-reveal schemes
    • Private transaction pools
    • Fair ordering

Conclusion

This Smart Modules system provides a comprehensive, modular DeFi infrastructure with:

  • Flexible AMM: Simple but effective liquidity pool
  • Gasless Transactions: EIP-712 meta-transactions
  • Upgradeable Fees: Future-proof fee management
  • Secure Vault: Multi-signature fund management
  • Role-Based Access: Granular permission system

The system is designed for:

  • Security: Multiple layers of protection
  • Modularity: Independent, composable components
  • Upgradeability: Can evolve with needs
  • Gas Efficiency: Optimized for on-chain operations

All components are thoroughly tested and ready for deployment on Ethereum-compatible networks.


References


Document Version: 1.0
Last Updated: 2024
Maintained By: Smart Modules Development Team