Vault UX Improvements
This document provides comprehensive technical documentation for Noderr Protocol's institutional-grade ERC-7540 UX improvement contracts.
Overview
While ERC-7540 provides powerful async vault capabilities, the 2-step flow creates UX friction for users. Noderr Protocol has developed three complementary contracts that transform these "downsides" into competitive advantages:
| Contract | Purpose | Key Benefit |
|---|---|---|
| VaultRouter | Bundled UX with auto-claim | Single-transaction experience |
| AutoClaimKeeper | Keeper auto-claim service | Hands-free claim execution |
| InstantLiquidityPool | Instant liquidity AMM | Skip the wait entirely |
VaultRouter
The VaultRouter is the primary interface for users interacting with ERC-7540 vaults. It provides a single-transaction UX by handling request submission, fulfillment monitoring, and claim execution.
Key Features
- Single-Transaction UX: Users interact once; router handles the rest
- Auto-Claim Service: Automatic claim execution when requests are fulfilled
- Batch Operations: Deposit/redeem across multiple vaults in one transaction
- Gasless Transactions: EIP-712 signatures for gas-free operations
- Slippage Protection: Configurable minimum output guarantees
- Emergency Controls: Pause functionality for security incidents
Architecture
User → VaultRouter → ERC-7540 Vault
↓
AutoClaimKeeper
↓
Automatic Claim
Core Functions
Request Deposit with Auto-Claim
function requestDeposit(
address vault,
uint256 assets,
uint256 minShares,
address receiver,
bool autoClaim
) external returns (uint256 requestId);
Parameters:
vault: The ERC-7540 vault addressassets: Amount of underlying tokens to depositminShares: Minimum shares to receive (slippage protection)receiver: Address to receive the vault sharesautoClaim: Enable automatic claim when fulfilled (0.1% fee)
Example:
// Deposit 1000 tUSDC with auto-claim enabledawait vaultRouter.requestDeposit(
conservativeVaultAddress,
parseUnits('1000', 18),
parseUnits('990', 18), // Accept up to 1% slippage
userAddress,
true// Enable auto-claim
);
Batch Deposit
function batchDeposit(
BatchDepositParams[] calldata params,
address receiver,
bool autoClaim
) external;
struct BatchDepositParams {
address vault;
uint256 assets;
uint256 minShares;
}
Deposit to multiple vaults in a single transaction, saving 50-70% on gas costs.
Example:
// Deposit to 3 vaults at onceawait vaultRouter.batchDeposit([
{ vault: conservativeVault, assets: parseUnits('500', 18), minShares: parseUnits('495', 18) },
{ vault: moderateVault, assets: parseUnits('300', 18), minShares: parseUnits('297', 18) },
{ vault: aggressiveVault, assets: parseUnits('200', 18), minShares: parseUnits('196', 18) }
], userAddress, true);
Gasless Deposit (EIP-712)
function depositWithPermit(
address vault,
uint256 assets,
uint256 minShares,
address receiver,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 requestId);
Users sign a message offchain; relayers submit the transaction and pay gas.
Fee Structure
| Service | Fee | Description |
|---|---|---|
| Standard Request | 0% | No fee for manual claim |
| Auto-Claim | 0.1% | Deducted from claimed amount |
| Gasless | 2%+ | Covers gas + relayer profit |
Configuration
| Parameter | Default | Description |
|---|---|---|
defaultTimeout | 1 hour | Request expiration time |
autoClaimFeeBps | 10 (0.1%) | Fee for auto-claim service |
AutoClaimKeeper
The AutoClaimKeeper enables keeper nodes to earn rewards by executing auto-claims for users. It integrates with TrustFingerprint for reputation-based reward scaling.
Key Features
- Keeper Registration: Stake NODR to become a keeper
- TrustFingerprint Integration: Higher trust = higher rewards
- Batch Execution: Process multiple claims efficiently
- Performance Tracking: Success rate, gas usage, rewards
- Slashing Mechanism: Penalties for failed executions
Becoming a Keeper
function registerKeeper(uint256 stake) external payable;
Requirements:
- Minimum TrustFingerprint: 0.70 (
MIN_TRUST_SCORE = 700in contract) - Stake: any amount sent as
msg.value(no enforced minimum)
Executing Claims
// Execute single deposit claim
function executeDepositClaim(
address user,
address vault,
address receiver
) external;
// Execute single redeem claim
function executeRedeemClaim(
address user,
address vault,
address receiver
) external;
// Batch execute multiple claims
function batchExecuteClaims(
ClaimParams[] calldata deposits,
ClaimParams[] calldata redeems
) external;
Reward Calculation
Base Reward = claimValue × baseRewardBps / 10000
Trust Bonus = Base Reward × (trustScore / 100) × trustBonusBps / 10000
Total Reward = Base Reward + Trust Bonus
Example:
- Claim value: 10,000 tUSDC
- Base reward rate: 0.1%
- TrustFingerprint: 0.85
- Trust bonus rate: 0.05%
Base Reward = 10,000 × 0.001 = 10 tUSDC
Trust Bonus = 10 × 0.85 × 0.0005 = 0.00425 tUSDC
Total Reward = 10.00425 tUSDC
Keeper Metrics
struct KeeperMetrics {
uint256 totalClaims; // Total claims executed
uint256 successfulClaims; // Successful executions
uint256 failedClaims; // Failed executions
uint256 totalGasUsed; // Cumulative gas usage
uint256 totalRewards; // Cumulative rewards earned
uint256 lastClaimTime; // Timestamp of last claim
}
Slashing Conditions
| Condition | Penalty |
|---|---|
| Failed execution | 0.1% of stake |
| >10% failure rate | Temporary suspension |
| Malicious behavior | Full stake slash |
InstantLiquidityPool
The InstantLiquidityPool provides immediate deposit/withdrawal execution for users who prefer speed over cost. LPs earn fees from impatient users.
Key Features
- Instant Deposits: Skip the 1-2 hour wait
- Instant Redemptions: Immediate asset return
- Dynamic Pricing: 2-5% fee based on utilization
- LP Rewards: Earn fees by providing liquidity
- Automated Rebalancing: Pool maintains optimal levels
How It Works
Standard Flow (1-2 hours):
User → requestDeposit → [wait] → claimDeposit → Shares
Instant Flow (immediate):
User → instantDeposit → Shares (pay 2-5% premium)
For Users: Instant Operations
Instant Deposit
function instantDeposit(
address vault,
uint256 assets,
uint256 minShares,
address receiver
) external returns (uint256 shares);
Example:
// Instant deposit with 3% feeconst shares = await instantLiquidityPool.instantDeposit(
conservativeVaultAddress,
parseUnits('1000', 18),
parseUnits('950', 18), // Accept up to 5% slippage (includes fee)
userAddress
);
Instant Redeem
function instantRedeem(
address vault,
uint256 shares,
uint256 minAssets,
address receiver
) external returns (uint256 assets);
For LPs: Providing Liquidity
Add Liquidity
function addLiquidity(
address vault,
uint256 assets,
uint256 shares
) external;
LPs can provide:
- Asset liquidity: tUSDC (the vault underlying asset) for instant deposits
- Share liquidity: Vault shares for instant redemptions
Remove Liquidity
function removeLiquidity(
address vault,
uint256 assets,
uint256 shares
) external;
Claim Fees
function claimFees(address vault) external;
Fee Structure
The fee is calculated using a linear formula based on pool utilization:
feeBps = MIN_FEE_BPS + ((MAX_FEE_BPS - MIN_FEE_BPS) × utilization) / 10000
= 200 + (300 × utilization / 10000)
| Utilization | Fee (approx.) |
|---|---|
| 0% | 2.0% |
| 25% | 2.75% |
| 50% | 3.5% |
| 75% | 4.25% |
| 100% | 5.0% |
Fee scales continuously and linearly, not in discrete steps.
Fee Distribution:
- 90% to LPs (proportional to stake)
- 10% to protocol treasury
LP Economics
Important: Returns to instant-liquidity LPs are fee income driven entirely by instant-flow volume, fee tier, pool size, and competition among LPs. They are not a protocol yield and are separate from Noderr's canonical yield model (vault depositors target ~10% blended; the combined vault + node target is 8-28%). The figures below are illustrative of the fee-share mechanic only and are not projected, expected, or guaranteed returns.
Illustrative mechanic (not a yield projection):
- LP provides 10,000 tUSDC liquidity
- Suppose the pool processes 50,000 tUSDC/day of instant flow at a 3% average fee
- Gross daily fees: 1,500 tUSDC (3% of 50,000)
- LP share at 90% fee distribution, holding 10% of the pool: 135 tUSDC/day
Realized returns depend on actual instant-flow volume, the prevailing utilization-based fee, the LP's share of the pool, and competition. Sustained high volume at these assumptions would be exceptional; in practice instant-flow demand is variable and may be low, so LPs should not assume the illustrative throughput above.
Integration Guide
Recommended User Flow
1. Check instant liquidity availability
2. If available and user prefers speed → Use InstantLiquidityPool
3. If user prefers cost savings → Use VaultRouter with auto-claim
4. If user wants full control → Use VaultRouter without auto-claim
TypeScript Integration
import { parseUnits } from'viem';
// Option 1: Instant deposit (immediate, 2-5% fee)const instantShares = await instantLiquidityPool.instantDeposit(
vaultAddress,
parseUnits('1000', 18),
parseUnits('950', 18),
userAddress
);
// Option 2: Auto-claim deposit (1-2 hours, 0.1% fee)await vaultRouter.requestDeposit(
vaultAddress,
parseUnits('1000', 18),
parseUnits('990', 18),
userAddress,
true// auto-claim
);
// Option 3: Manual deposit (1-2 hours, 0% fee)await vaultRouter.requestDeposit(
vaultAddress,
parseUnits('1000', 18),
parseUnits('990', 18),
userAddress,
false// manual claim
);
// Later: manually claimconst shares = await vaultRouter.claimDeposit(vaultAddress, userAddress);
Solidity Integration
import "./interfaces/IVaultRouter.sol";
import "./interfaces/IInstantLiquidityPool.sol";
contract MyProtocol {
IVaultRouter public vaultRouter;
IInstantLiquidityPool public instantPool;
function smartDeposit(
address vault,
uint256 amount,
bool preferSpeed
) external {
if (preferSpeed && instantPool.hasLiquidity(vault, amount)) {
// Instant deposit
instantPool.instantDeposit(vault, amount, 0, msg.sender);
} else {
// Auto-claim deposit
vaultRouter.requestDeposit(vault, amount, 0, msg.sender, true);
}
}
}
Deployed Contracts
| Contract | Address | Network |
|---|---|---|
| VaultRouter | Pending Deployment | Base Sepolia |
| AutoClaimKeeper | Pending Deployment | Base Sepolia |
| InstantLiquidityPool | Pending Deployment | Base Sepolia |
Security Considerations
Access Control
| Contract | Role | Permissions |
|---|---|---|
| VaultRouter | OPERATOR_ROLE | Execute auto-claims |
| VaultRouter | PAUSER_ROLE | Emergency pause |
| AutoClaimKeeper | KEEPER_ROLE | Execute claims |
| InstantLiquidityPool | REBALANCER_ROLE | Trigger rebalancing |
Emergency Functions
All contracts implement:
pause()/unpause()- Halt operationsemergencyWithdraw()- Admin asset recovery- UUPS upgradeable pattern for security patches
Audit Status
These contracts are pending third-party security audit. Use on testnet only until audits are complete.
Related Documentation
- Vault Contracts - ERC-7540 vault documentation
- Contract Addresses - Deployed contract addresses
- Node Operators Guide - Running keeper nodes
- Deposit Guide - User deposit guide
Last Updated: December 28, 2025
Version: 1.0