Skip to main content

Liquidity Cache Technical Reference

Contract Overview​

The LiquidityCache contract is a comprehensive ERC4626-compliant vault that serves as both a liquidity pool and staking mechanism for the MCAP gaming platform. It extends OpenZeppelin's battle-tested contracts to provide secure, efficient liquidity management.

Contract Architecture​

Inheritance Hierarchy​

LiquidityCache
├── ILiquidityCache (Interface)
├── ERC4626 (Vault Standard)
│ └── ERC20 (Token Standard)
├── AccessControl (Role-based permissions)
├── Pausable (Emergency controls)
└── ReentrancyGuard (Attack protection)

Core Dependencies​

  • OpenZeppelin Contracts v4.x+
  • Solidity ^0.8.28
  • ERC20 compatible underlying asset

Contract Specification​

Constructor​

constructor(IERC20 _asset)

Parameters:

  • _asset: The ERC20 token used as the underlying asset for the vault

Behavior:

  • Initializes ERC4626 vault with the specified asset
  • Sets share token name to "Liquidity Cache Share" (symbol: "LCS")
  • Grants DEFAULT_ADMIN_ROLE and PAYOUT_ROLE to deployer

Access Control​

Roles​

RoleKeccak256 HashDescription
DEFAULT_ADMIN_ROLE0x00...Can pause/unpause, grant/revoke roles
PAYOUT_ROLEkeccak256("PAYOUT_ROLE")Can remove assets for payouts

Role Functions​

// Admin functions
function pause() external onlyRole(DEFAULT_ADMIN_ROLE)
function unpause() external onlyRole(DEFAULT_ADMIN_ROLE)

// Payout functions
function removeAssets(uint256 amount, address receiver) external onlyPayoutRole

Core Functions​

Asset Management​

Adding Assets (Game Profits)​

function addAssets(uint256 amount, address caller) external nonReentrant

Purpose: Allows external parties to add assets to the pool without minting shares, typically used for depositing game profits.

Parameters:

  • amount: Amount of underlying assets to add
  • caller: Address that will provide the assets

Requirements:

  • Caller must have approved the contract to spend amount tokens
  • Contract must not be paused
  • Must be non-reentrant

Events: Emits AssetsAdded(amount, caller)

Removing Assets (Payouts)​

function removeAssets(uint256 amount, address receiver) external onlyPayoutRole whenNotPaused nonReentrant

Purpose: Allows authorized parties to remove assets for payouts.

Parameters:

  • amount: Amount of assets to remove
  • receiver: Address to receive the assets

Requirements:

  • Caller must have PAYOUT_ROLE
  • Contract must not be paused
  • Sufficient assets must be available in pool
  • Must be non-reentrant

Events: Emits AssetsRemoved(amount, receiver)

ERC4626 Functions (Overridden)​

All standard ERC4626 functions are overridden to add pausability and reentrancy protection:

Deposit​

function deposit(uint256 assets, address receiver) 
public virtual override whenNotPaused nonReentrant
returns (uint256 shares)

Mint​

function mint(uint256 shares, address receiver) 
public virtual override whenNotPaused nonReentrant
returns (uint256 assets)

Withdraw​

function withdraw(uint256 assets, address receiver, address owner) 
public virtual override whenNotPaused nonReentrant
returns (uint256 shares)

Redeem​

function redeem(uint256 shares, address receiver, address owner) 
public virtual override whenNotPaused nonReentrant
returns (uint256 assets)

Events​

Custom Events​

event AssetsAdded(uint256 amount, address indexed sender);
event AssetsRemoved(uint256 amount, address indexed receiver);

Inherited Events​

From ERC4626/ERC20:

  • Transfer(address indexed from, address indexed to, uint256 value)
  • Approval(address indexed owner, address indexed spender, uint256 value)
  • Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares)
  • Withdraw(address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares)

From AccessControl:

  • RoleGranted(bytes32 indexed role, address indexed account, address indexed sender)
  • RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender)

From Pausable:

  • Paused(address account)
  • Unpaused(address account)

Integration Patterns​

For Gaming Platforms​

Adding Game Profits​

// 1. Approve tokens
IERC20(underlyingToken).approve(liquidityCacheAddress, profitAmount);

// 2. Add assets to pool
LiquidityCache(liquidityCacheAddress).addAssets(profitAmount, address(this));

Processing Payouts​

// Only accounts with PAYOUT_ROLE can call this
LiquidityCache(liquidityCacheAddress).removeAssets(payoutAmount, userAddress);

For Stakers​

Staking (Depositing)​

// 1. Approve tokens
IERC20(underlyingToken).approve(liquidityCacheAddress, stakeAmount);

// 2. Deposit and receive shares
uint256 shares = LiquidityCache(liquidityCacheAddress).deposit(stakeAmount, userAddress);

Unstaking (Withdrawing)​

// Option 1: Withdraw specific asset amount
uint256 sharesBurned = LiquidityCache(liquidityCacheAddress).withdraw(
assetAmount,
userAddress,
userAddress
);

// Option 2: Redeem specific share amount
uint256 assetsReceived = LiquidityCache(liquidityCacheAddress).redeem(
shareAmount,
userAddress,
userAddress
);

Mathematical Formulas​

Share Calculation​

When depositing assets:

shares = assets * totalSupply() / totalAssets()

When minting shares:

assets = shares * totalAssets() / totalSupply()

Exchange Rate​

exchangeRate = totalAssets() / totalSupply()

Yield Calculation​

For a user who deposited at time T1 and checks at time T2:

initialShareValue = totalAssets(T1) / totalSupply(T1)
currentShareValue = totalAssets(T2) / totalSupply(T2)
yield = (currentShareValue - initialShareValue) / initialShareValue

Gas Optimization​

Typical Gas Costs​

FunctionEstimated Gas
deposit()~100,000
withdraw()~80,000
addAssets()~60,000
removeAssets()~40,000

Note: Gas costs vary based on network conditions and contract state

Optimization Tips​

  1. Batch Operations: Group multiple deposits/withdrawals
  2. Approve Once: Use maximum approval to avoid repeated approval transactions
  3. Monitor Gas Prices: Execute during low-traffic periods
  4. Preview Functions: Use view functions to calculate before executing

Security Considerations​

Built-in Protections​

  1. Reentrancy Guard: Prevents reentrancy attacks
  2. Access Control: Role-based function restrictions
  3. Pausability: Emergency stop mechanism
  4. Safe Transfers: Protection against malicious tokens
  5. Overflow Protection: Solidity 0.8+ built-in overflow checks

Best Practices for Integrators​

  1. Verify Contract Address: Always verify you're interacting with the correct contract
  2. Check Return Values: Verify function calls succeed
  3. Handle Edge Cases: Account for scenarios like insufficient liquidity
  4. Monitor Events: Listen to events for transaction confirmation
  5. Test Thoroughly: Test all integration paths

Potential Risks​

  1. Smart Contract Risk: Bugs in contract code
  2. Admin Key Risk: Compromise of admin private keys
  3. Liquidity Risk: Insufficient assets for withdrawals
  4. Market Risk: Underlying asset price volatility

Interface Definition​

interface ILiquidityCache {
function addAssets(uint256 amount, address caller) external;
function removeAssets(uint256 amount, address receiver) external;

// Standard ERC4626 interface
function asset() external view returns (address);
function totalAssets() external view returns (uint256);
function convertToShares(uint256 assets) external view returns (uint256);
function convertToAssets(uint256 shares) external view returns (uint256);
function maxDeposit(address receiver) external view returns (uint256);
function previewDeposit(uint256 assets) external view returns (uint256);
function deposit(uint256 assets, address receiver) external returns (uint256);
function maxMint(address receiver) external view returns (uint256);
function previewMint(uint256 shares) external view returns (uint256);
function mint(uint256 shares, address receiver) external returns (uint256);
function maxWithdraw(address owner) external view returns (uint256);
function previewWithdraw(uint256 assets) external view returns (uint256);
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256);
function maxRedeem(address owner) external view returns (uint256);
function previewRedeem(uint256 shares) external view returns (uint256);
function redeem(uint256 shares, address receiver, address owner) external returns (uint256);
}

Testing Framework​

Unit Test Categories​

  1. Access Control Tests

    • Role assignment and revocation
    • Function restrictions
    • Emergency pause functionality
  2. Asset Management Tests

    • Adding assets without minting shares
    • Removing assets with proper authorization
    • Asset calculation accuracy
  3. ERC4626 Compliance Tests

    • Deposit/withdrawal flows
    • Share calculation accuracy
    • Preview function consistency
  4. Security Tests

    • Reentrancy attack prevention
    • Overflow/underflow protection
    • Malicious token handling

Integration Test Scenarios​

  1. Multi-user Staking

    • Multiple users deposit at different times
    • Profits added between deposits
    • Verify share value calculations
  2. Gaming Platform Integration

    • Simulate game profit additions
    • Test payout processing
    • Verify liquidity management
  3. Edge Cases

    • Empty pool operations
    • Maximum withdrawal attempts
    • Pause/unpause scenarios

Deployment Guide​

Prerequisites​

  1. Underlying Asset Contract: Deployed ERC20 token
  2. Network Configuration: Target blockchain network
  3. Admin Wallet: Secure wallet for admin functions
  4. Gas Budget: Sufficient native tokens for deployment

Deployment Steps​

// 1. Deploy with constructor parameters
LiquidityCache liquidityCache = new LiquidityCache(
IERC20(underlyingTokenAddress)
);

// 2. Grant additional roles if needed
liquidityCache.grantRole(PAYOUT_ROLE, payoutOperatorAddress);

// 3. Verify contract on explorer
// 4. Initialize with initial liquidity if desired

Post-Deployment Verification​

  1. Contract Verification: Verify source code on block explorer
  2. Role Assignment: Confirm correct roles are assigned
  3. Functionality Testing: Test all major functions
  4. Integration Testing: Test with actual gaming platforms

Monitoring and Maintenance​

Key Metrics to Monitor​

  1. Total Assets: Track pool growth over time
  2. Total Shares: Monitor share supply changes
  3. Exchange Rate: Watch for significant changes
  4. Asset Addition Events: Monitor profit deposits
  5. Asset Removal Events: Track payout activity

Alerting Recommendations​

  1. Large Withdrawals: Alert on significant asset removals
  2. Exchange Rate Changes: Monitor for unusual fluctuations
  3. Failed Transactions: Track transaction failures
  4. Role Changes: Alert on admin role modifications
  5. Pause Events: Immediate notification of contract pausing

Maintenance Tasks​

  1. Regular Audits: Periodic security reviews
  2. Performance Monitoring: Track gas costs and optimization opportunities
  3. Upgrade Planning: Plan for potential contract upgrades
  4. Documentation Updates: Keep documentation current with changes