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.

VaultAddressRiskStrategy Profile
Conservative0x49f747BBac988Cd628a5D79AAdF865EBaDe6a34fLowCapital preservation
Moderate0x4B183AfF072C7DFf09bc8eB4B7f59eB3D030EEdcMediumBalanced growth
Aggressive0x1444Fb96961fD9b8Fc14Aa4D9A7198465b7d8CA3HighMaximum growth
Hedged0xDDa7655AD3c53f0F7EC5CCbc346c18baB53C5a92LowDownside-protected
Inverse0xE2E4d181f2eAd5B380026Ab71F49FEBCb93f641cHighInverse/short exposure
Configurable0x53A2EfFaDE21055b8f81e1dE96dC5cfc29B75a83MediumDAO-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 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 tUSDC
maxRiskScoreMaximum risk score for strategies30-100
managementFeeAnnual management fee0% (every vault)
performanceFeeHigh-water-mark fee on profits, charged only from the Trading bucket10%–25%, set per vault (see Fee Structure)
hurdleRatePer-vault soft hurdle return that must be exceeded before the performance fee applies4%–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:

VaultPerformance FeeSoft Hurdle
Conservative10%4%
Moderate15%6%
Aggressive20%8%
Hedged15%4%
Inverse20%8%
Configurable15% (DAO-configurable)6%
PredictionMarkets25%15%

PredictionMarkets is planned and not yet deployed; its parameters are shown for reference.

Fee TypeRateDescription
Management Fee0%No annual management fee, on every vault
Deposit Fee0%No fee to deposit
Withdrawal Fee0%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:

RolePermissions
DEFAULT_ADMIN_ROLEGrant/revoke roles, emergency functions
FULFILLER_ROLECall fulfillDeposit/fulfillRedeem
STRATEGY_MANAGER_ROLEUpdate strategy allocations
PAUSER_ROLEPause/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
);


Last Updated: December 28, 2025

Version: 1.0

results matching ""

    No results matching ""