Vault Contracts

This document provides comprehensive technical documentation for the Noderr Protocol's ERC-7540 vault contracts.


Overview

Noderr Protocol vaults implement the ERC-7540 standard, an extension of ERC-4626 that enables asynchronous deposit and redeem operations. This architecture is designed for institutional-grade DeFi, supporting crosschain strategies, real-world assets (RWA), and complex yield generation mechanisms that require time for settlement.

Why ERC-7540?

Traditional ERC-4626 vaults execute deposits and withdrawals synchronously, which limits their ability to:

  • Execute crosschain strategies
  • Integrate with real-world assets requiring settlement time
  • Implement sophisticated risk management with position unwinding
  • Support institutional compliance requirements

ERC-7540 solves these limitations by introducing a 2-step async flow:

Deposit:  requestDeposit() → [wait for fulfillment] → claimDeposit()
Redeem:   requestRedeem()  → [wait for fulfillment] → claimRedeem()

Deployed Contracts

All vault contracts are deployed on Base Sepolia testnet using the UUPS upgradeable proxy pattern.

VaultAddressRiskTarget APY
ConservativeVault75400xd62f6c4Fe1444Dafbe3dBd0163C4B77A3C41Af84Low5-10%
ModerateVault75400xd2Ba1B10BDC972188dC5bb9CcA64d1Aac06E5025Medium10-20%
AggressiveVault75400x43974CC939C6987c4Fbf724bcab8402e5658fa52High20-35%
HedgedVault75400xB88f9871Ced85c2097bcc2d94daf7E88ED516476Low8-15%
InverseVault75400x61f2c3f6a45E5B5A648b91e7756A651DA8cfF5D2HighVariable
ConfigurableVault75400x852f0221a2705DdE05505B510192e13F06c1d086MediumVariable

ERC-7540 Interface

Core Functions

Request Deposit

function requestDeposit(
uint256 assets,
address controller,
address owner
) external returns (uint256 requestId);

Initiates an async deposit request. Assets are transferred from the owner to the vault, and a request ID is returned for tracking.

Parameters:

  • assets: Amount of underlying tokens to deposit
  • controller: Address that can claim the deposit (usually same as owner)
  • owner: Address that owns the assets being deposited

Returns:requestId - Unique identifier for tracking the request

Claim Deposit

function claimDeposit(
uint256 assets,
address receiver,
address controller
) external returns (uint256 shares);

Claims shares after a deposit request has been fulfilled.

Parameters:

  • assets: Amount of assets to claim shares for
  • receiver: Address to receive the vault shares
  • controller: Address that controls the request

Returns:shares - Number of vault shares minted

Request Redeem

function requestRedeem(
uint256 shares,
address controller,
address owner
) external returns (uint256 requestId);

Initiates an async redeem request. Shares are transferred from the owner to the vault.

Claim Redeem

function claimRedeem(
uint256 shares,
address receiver,
address controller
) external returns (uint256 assets);

Claims underlying assets after a redeem request has been fulfilled.

Status Functions

// Check pending deposit amount
function pendingDepositRequest(uint256 requestId, address controller)
external view returns (uint256);
// Check claimable deposit amount
function claimableDepositRequest(uint256 requestId, address controller)
external view returns (uint256);
// Check pending redeem amount
function pendingRedeemRequest(uint256 requestId, address controller)
external view returns (uint256);
// Check claimable redeem amount
function claimableRedeemRequest(uint256 requestId, address controller)
external view returns (uint256);

Operator Management

// Set an operator who can claim on your behalf
function setOperator(address operator, bool approved) external returns (bool);
// Check if an address is an operator for a controller
function isOperator(address controller, address operator) external view returns (bool);

Vault Configuration

Each vault has configurable parameters set at deployment:

ParameterDescriptionTypical Values
fulfillmentDelayMinimum time before requests can be fulfilled1-2 hours
minDepositMinimum deposit amount100-250 NODR
maxRiskScoreMaximum risk score for strategies30-100
managementFeeAnnual management fee0%
performanceFeeFee on profits above hurdle20%
hurdleRateMinimum return before performance fee8%

Async Flow Diagram

User                    Vault                   Keeper/Fulfiller
|                       |                           |
|-- requestDeposit() -->|                           |
|<-- requestId ---------|                           |
|                       |                           |
|        [assets held in vault, request pending]    |
|                       |                           |
|                       |<-- fulfillDeposit() ------|
|                       |   (after delay elapsed)   |
|                       |                           |
|-- claimDeposit() ---->|                           |
|<-- shares ------------|                           |
|                       |                           |

Integration Examples

JavaScript/TypeScript (with viem)

import { parseUnits } from'viem';
// Request a depositconst requestId = await vaultContract.write.requestDeposit([
parseUnits('1000', 18),  // 1000 NODR
userAddress,              // controller
userAddress               // owner
]);
// Check if claimable (after fulfillment)const claimable = await vaultContract.read.claimableDepositRequest([
requestId,
userAddress
]);
// Claim sharesif (claimable > 0n) {
const shares = await vaultContract.write.claimDeposit([
claimable,
userAddress,  // receiver
userAddress   // controller
]);
}

Solidity Integration

import "./interfaces/IERC7540.sol";
contract VaultIntegration {
IERC7540 public vault;
function depositToVault(uint256 amount) external {
// Approve vault to spend tokens
IERC20(vault.asset()).approve(address(vault), amount);
// Request deposit
uint256 requestId = vault.requestDeposit(
amount,
msg.sender,
msg.sender
);
// Store requestId for later claiming
userRequests[msg.sender] = requestId;
}
function claimFromVault() external {
uint256 requestId = userRequests[msg.sender];
uint256 claimable = vault.claimableDepositRequest(requestId, msg.sender);
require(claimable > 0, "Nothing to claim");
vault.claimDeposit(claimable, msg.sender, msg.sender);
}
}

Fee Structure

All ERC-7540 vaults share a consistent fee structure:

Fee TypeRateDescription
Management Fee0%No annual management fee
Performance Fee20%Applied only to returns above hurdle rate
Hurdle Rate8%Minimum return before performance fee applies

Example:

  • Vault generates 15% return
  • Hurdle rate: 8%
  • Excess return: 15% - 8% = 7%
  • Performance fee: 7% × 20% = 1.4%
  • Net return to user: 15% - 1.4% = 13.6%

Security Considerations

Access Control

Each vault implements role-based access control:

RolePermissions
DEFAULT_ADMIN_ROLEGrant/revoke roles, emergency functions
FULFILLER_ROLECall fulfillDeposit/fulfillRedeem
STRATEGY_MANAGER_ROLEUpdate strategy allocations
PAUSER_ROLEPause/unpause vault operations

Emergency Functions

// Pause all vault operations
function pause() external onlyRole(PAUSER_ROLE);
// Unpause vault operations
function unpause() external onlyRole(PAUSER_ROLE);
// Emergency withdrawal (admin only)
function emergencyWithdraw(address token, uint256 amount) external onlyRole(DEFAULT_ADMIN_ROLE);

Audit Status

The ERC-7540 vault contracts have passed internal testing with 24/24 tests passing. Third-party security audit is pending for mainnet deployment.


Events

// Emitted when a deposit is requested
event DepositRequest(
address indexed controller,
address indexed owner,
uint256 indexed requestId,
address sender,
uint256 assets
);
// Emitted when a deposit is claimed
event DepositClaim(
address indexed controller,
address indexed receiver,
uint256 indexed requestId,
uint256 assets,
uint256 shares
);
// Emitted when a redeem is requested
event RedeemRequest(
address indexed controller,
address indexed owner,
uint256 indexed requestId,
address sender,
uint256 shares
);
// Emitted when a redeem is claimed
event RedeemClaim(
address indexed controller,
address indexed receiver,
uint256 indexed requestId,
uint256 shares,
uint256 assets
);
// Emitted when an operator is set
event OperatorSet(
address indexed controller,
address indexed operator,
bool approved
);


Last Updated: December 28, 2025

Version: 1.0

results matching ""

    No results matching ""