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
The live user-facing vaults are six per-tier EIP-2535 Diamonds (ERC-7540 async), deployed on Base Sepolia (chainId 84532) and denominated in tUSDC (a mintable test USDC available via a faucet). Each tier is its own single-vault Diamond, and every vault uses a two-bucket design: a principal-protected Floor bucket plus an Active Trading bucket. Addresses below are the live dApp configuration set; always confirm against the dApp config before integrating.
| Vault | Address | Risk | Strategy Profile |
|---|---|---|---|
| Conservative | 0x49f747BBac988Cd628a5D79AAdF865EBaDe6a34f | Low | Capital preservation |
| Moderate | 0x4B183AfF072C7DFf09bc8eB4B7f59eB3D030EEdc | Medium | Balanced growth |
| Aggressive | 0x1444Fb96961fD9b8Fc14Aa4D9A7198465b7d8CA3 | High | Maximum growth |
| Hedged | 0xDDa7655AD3c53f0F7EC5CCbc346c18baB53C5a92 | Low | Downside-protected |
| Inverse | 0xE2E4d181f2eAd5B380026Ab71F49FEBCb93f641c | High | Inverse/short exposure |
| Configurable | 0x53A2EfFaDE21055b8f81e1dE96dC5cfc29B75a83 | Medium | DAO-configurable |
Yield note: Depositor yield targets a blended ~10% across vaults (Floor allocation ~85% at ~8% plus the Active Trading allocation ~15% at ~20%). The 8–28% range refers to the combined return available when a depositor also stakes NODR and runs a node; it is never a vault-only figure. Higher APYs cited for individual underlying protocols reflect external-protocol potential, not Noderr vault depositor yield. All figures are forward-looking targets on testnet, not guaranteed returns.
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 tUSDC |
maxRiskScore | Maximum risk score for strategies | 30-100 |
managementFee | Annual management fee | 0% (every vault) |
performanceFee | High-water-mark fee on profits, charged only from the Trading bucket | 10%–25%, set per vault (see Fee Structure) |
hurdleRate | Per-vault soft hurdle return that must be exceeded before the performance fee applies | 4%–15%, set per vault (see Fee Structure) |
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', 6), // 1000 tUSDC (underlying asset)
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
Every vault charges 0% management fee. The only fee is a performance fee, and it is:
- High-water-mark based — charged only when NAV per share rises above its prior peak, so a depositor is never charged twice for the same gains.
- Charged strictly from the Trading bucket — the principal-protected Floor bucket is never touched by the performance fee.
- Subject to a per-vault soft hurdle — the fee only applies on returns above the vault's hurdle rate.
The performance fee and soft hurdle are configured per vault:
| Vault | Performance Fee | Soft Hurdle |
|---|---|---|
| Conservative | 10% | 4% |
| Moderate | 15% | 6% |
| Aggressive | 20% | 8% |
| Hedged | 15% | 4% |
| Inverse | 20% | 8% |
| Configurable | 15% (DAO-configurable) | 6% |
| PredictionMarkets | 25% | 15% |
PredictionMarkets is planned and not yet deployed; its parameters are shown for reference.
| Fee Type | Rate | Description |
|---|---|---|
| Management Fee | 0% | No annual management fee, on every vault |
| Deposit Fee | 0% | No fee to deposit |
| Withdrawal Fee | 0% | No fee to withdraw |
Example (Moderate Vault):
- User deposits: 10,000 tUSDC
- Trading bucket generates a gain that lifts NAV/share to a new high-water mark, net of the 6% soft hurdle: 1,000 tUSDC of fee-eligible profit; illustrative, aligned with the ~10% blended vault target
- Performance fee (15% of the fee-eligible profit): 150 tUSDC
- Net return to user: 10,850 tUSDC
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 |
DEFAULT_ADMIN_ROLE and upgrade authority for the core protocol ultimately resolve to a MultiSigTimelock (7-day delay) driven by a 2-of-3 Gnosis Safe — the protocol's on-chain governance/upgrade authority. There is no off-chain (e.g. Snapshot) governance path.
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