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.
| Vault | Address | Risk | Target APY |
|---|---|---|---|
| ConservativeVault7540 | 0xd62f6c4Fe1444Dafbe3dBd0163C4B77A3C41Af84 | Low | 5-10% |
| ModerateVault7540 | 0xd2Ba1B10BDC972188dC5bb9CcA64d1Aac06E5025 | Medium | 10-20% |
| AggressiveVault7540 | 0x43974CC939C6987c4Fbf724bcab8402e5658fa52 | High | 20-35% |
| HedgedVault7540 | 0xB88f9871Ced85c2097bcc2d94daf7E88ED516476 | Low | 8-15% |
| InverseVault7540 | 0x61f2c3f6a45E5B5A648b91e7756A651DA8cfF5D2 | High | Variable |
| ConfigurableVault7540 | 0x852f0221a2705DdE05505B510192e13F06c1d086 | Medium | Variable |
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 depositcontroller: 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 forreceiver: Address to receive the vault sharescontroller: 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:
| Parameter | Description | Typical Values |
|---|---|---|
fulfillmentDelay | Minimum time before requests can be fulfilled | 1-2 hours |
minDeposit | Minimum deposit amount | 100-250 NODR |
maxRiskScore | Maximum risk score for strategies | 30-100 |
managementFee | Annual management fee | 0% |
performanceFee | Fee on profits above hurdle | 20% |
hurdleRate | Minimum return before performance fee | 8% |
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 Type | Rate | Description |
|---|---|---|
| Management Fee | 0% | No annual management fee |
| Performance Fee | 20% | Applied only to returns above hurdle rate |
| Hurdle Rate | 8% | 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:
| Role | Permissions |
|---|---|
DEFAULT_ADMIN_ROLE | Grant/revoke roles, emergency functions |
FULFILLER_ROLE | Call fulfillDeposit/fulfillRedeem |
STRATEGY_MANAGER_ROLE | Update strategy allocations |
PAUSER_ROLE | Pause/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
);
Related Documentation
- Contract Addresses - Full list of deployed contract addresses
- ERC-7540 Specification - Official EIP documentation
- Deposit Guide - User guide for depositing
- Withdraw Guide - User guide for withdrawing
Last Updated: December 28, 2025
Version: 1.0