Skip to content

Commit 054a51a

Browse files
committed
[VEN-3197] technical article about VenusERC4626
1 parent 9973fd7 commit 054a51a

File tree

4 files changed

+321
-0
lines changed

4 files changed

+321
-0
lines changed
173 KB
Loading

.gitbook/assets/erc4626-deposit.png

439 KB
Loading

.gitbook/assets/erc4626-withdraw.png

330 KB
Loading
Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
# Venus Protocol's ERC-4626 Implementation
2+
3+
## Overview
4+
5+
Venus Protocol likes to introduce **native ERC-4626 vaults**, bringing standardized, composable yield vaults to the Venus ecosystem. This integration represents a significant advancement in making Venus's yield-bearing markets more accessible and composable within the broader DeFi ecosystem.
6+
7+
### Key Benefits:
8+
9+
- **Full ERC-4626 Compliance** – Interoperable with DeFi primitives (DAOs, aggregators, etc.)
10+
- **Native Venus Yield Integration** – Auto-compounding via vTokens
11+
- **Gas-Optimized Architecture** – Beacon proxy pattern for efficient deployments, to keep all vaults implementation contract the same.
12+
- **Secure & Upgradeable** – Governance-controlled upgrades and reward management
13+
14+
## Understanding ERC-4626
15+
16+
ERC-4626 is a tokenized vault standard designed to unify how yield-bearing assets are deposited, managed, and withdrawn in DeFi protocols. It builds on the ERC-20 token standard and introduces a consistent interface for vaults that accept a specific asset (like USDC) and issue shares representing ownership in the vault.
17+
18+
The primary goal of ERC-4626 is **standardization**—allowing developers to integrate with vaults without needing to understand their internal mechanics. Functions like deposit, withdraw, mint, and redeem follow predictable behaviors across all compliant contracts.
19+
20+
In essence, ERC-4626 makes it easier for users to earn yield on their assets, and for protocols to plug into vaults in a reliable, composable way—enhancing both usability and interoperability across the DeFi ecosystem.
21+
22+
#### Reference: https://eips.ethereum.org/EIPS/eip-4626
23+
24+
## The implementation of the Venus4626 vaults consists of two core smart contracts:
25+
26+
#### **1\. VenusERC4626Factory.sol - The factory contract for deploying standardized vaults**
27+
28+
- Deploys individual vaults for individual vTokens via **BeaconProxy**
29+
- Ensures deterministic addresses using **CREATE2**
30+
- Managed by Venus Governance
31+
32+
#### **2\. VenusERC4626.sol - The vault logic implementing ERC-4626 functionality**
33+
34+
- ERC-4626-compliant mint, deposit, redeem and withdraw functions
35+
- Integrates with Venus’s **vToken** interest accrual
36+
- Handles reward distribution (XVS, etc.)
37+
38+
## Architecture
39+
40+
<figure><img src="../../.gitbook/assets/erc-4626-flow-diagram.png" alt="Flow of funds related to Prime"><figcaption></figcaption></figure>
41+
42+
## **VenusERC4626Factory.sol: The Vault Factory**
43+
44+
### **Architecture Overview**
45+
46+
The factory contract implements a sophisticated deployment system using OpenZeppelin's upgradeability patterns:
47+
48+
```jsx
49+
contract VenusERC4626Factory is AccessControlledV8, MaxLoopsLimitHelper {
50+
UpgradeableBeacon public beacon;
51+
mapping(address vToken => ERC4626Upgradeable vault) public createdVaults;
52+
53+
function createERC4626(address vToken) external returns (ERC4626Upgradeable) {
54+
// Deployment logic...
55+
}
56+
}
57+
```
58+
59+
### **Core Components**
60+
61+
### **Beacon Proxy System**
62+
63+
- **UpgradeableBeacon**: Stores the current implementation address
64+
- **BeaconProxy**: Proxy delegates to beacon implementation
65+
- **CREATE2**: Deterministic deployment with fixed salt for beacon proxies
66+
67+
#### Benefits:
68+
69+
- Single implementation contract shared by all vaults
70+
- Gas-efficient deployments
71+
- Centralized upgrade capability
72+
73+
### **PoolRegistry Integration**
74+
75+
```jsx
76+
function createERC4626(address vToken) external {
77+
// Validate vToken is registered in PoolRegistry
78+
if (vToken != poolRegistry.getVTokenForAsset(comptroller, underlying)) {
79+
revert VenusERC4626Factory__InvalidVToken();
80+
}
81+
// Proceed with deployment...
82+
}
83+
```
84+
85+
This ensures:
86+
87+
- Only legitimate Venus vTokens can create vaults
88+
- Proper asset/vToken pairing
89+
- Compliance with Venus's risk parameters
90+
91+
### Key Features
92+
93+
- **Deterministic Deployment**: Uses a constant salt to enable deterministic address generation for ERC-4626 vaults(Proxies).
94+
- **Upgradeable Architecture**: Utilizes a beacon proxy pattern to support upgradeability of all deployed vaults via a single beacon.
95+
- **Vault Tracking**: Maintains a mapping `createdVaults` of vTokens to their corresponding deployed ERC-4626 vaults.
96+
- **Reward Routing**: Allows configuration of a centralized reward recipient for all vaults, supporting liquidity mining incentives.
97+
- **Permissioned Admin**: Restricted administrative operations (e.g., setting reward recipient, max loops) via Access Control Manager (ACM).
98+
99+
### Events
100+
101+
- **`CreateERC4626 (event)`**: Emitted when a new ERC-4626 vault is created for a vToken.
102+
- **`RewardRecipientUpdated (event)`**: Emitted when the reward recipient address is updated.
103+
104+
### Constants
105+
106+
- **`SALT (bytes32)`**: Constant salt used for deterministic deployment of vaults.
107+
108+
### State variables
109+
110+
- **`beacon (UpgradeableBeacon)`**: Stores the address of the beacon contract holding the ERC-4626 vault implementation.
111+
- **`poolRegistry (PoolRegistryInterface)`**: Reference to the Venus Pool Registry contract.
112+
- **`rewardRecipient (address)`**: Address designated to receive liquidity mining rewards.
113+
- **`createdVaults (mapping(address => ERC4626Upgradeable))`**: Maps vTokens to their deployed ERC-4626 vault instances.
114+
115+
### Functions
116+
117+
- **`initialize()`**: Initializes the factory with core configuration.
118+
- **`createERC4626(address vToken)`**: Creates a new ERC-4626 vault for the specified vToken.
119+
- **`computeVaultAddress(address vToken)`**: Returns the predicted address of a vault for a specific vToken.
120+
- **`setRewardRecipient(address newRecipient)`**: Updates the address receiving reward distributions (ACM-restricted).
121+
- **`setMaxLoopsLimit(uint256 loopsLimit)`**: Configures the maximum allowed loop iterations (ACM-restricted).
122+
123+
### **Security Considerations**
124+
125+
### **1\. Access Controls**
126+
127+
- **Admin-Only Functions** (via **AccessControlledV8**):
128+
129+
- **setRewardRecipient()**
130+
- **setMaxLoopsLimit()**
131+
- **upgradeBeacon()** (for emergency fixes)
132+
133+
### **2\. Input Validation**
134+
135+
- **ensureNonzeroAddress()** prevents invalid configurations.
136+
137+
### **Attack Surface Mitigation**
138+
139+
| **Threat Vector** | **Mitigation Strategy** |
140+
| ------------------ | ------------------------- |
141+
| Reentrancy | `nonReentrant` modifiers |
142+
| Invalid vTokens | PoolRegistry validation |
143+
| Governance attacks | ACM with timelocks |
144+
| Upgrade risks | Beacon ownership controls |
145+
146+
---
147+
148+
## VenusERC4626.sol: The Vault Implementation
149+
150+
### Core Architecture
151+
152+
The **VenusERC4626** contract serves as an ERC-4626 compliant wrapper around Venus's yield-bearing vTokens. It inherits from multiple OpenZeppelin and Venus-specific base contracts to provide a secure, feature-rich implementation:
153+
154+
```jsx
155+
contract VenusERC4626 is
156+
ERC4626Upgradeable,
157+
AccessControlledV8,
158+
MaxLoopsLimitHelper,
159+
ReentrancyGuardUpgradeable {
160+
// Implementation...
161+
}
162+
```
163+
164+
### Key Features
165+
166+
- **ERC-4626 Compliant**: Fully compliant with the ERC-4626 Tokenized Vault standard, enabling integrations with yield aggregators and frontends.
167+
- **vToken Wrapping**: Provides tokenized access to underlying vTokens with proportional interest accrual.
168+
- **Dual-Stage Initialization**: Separates base contract setup and access/reward configuration for modular deployment.
169+
- **Reward Claiming**: Allows vaults to claim accrued rewards and direct them to a predefined recipient.
170+
- **Failsafes and Admin Tools**: Includes recovery mechanisms like `sweepToken` and loop control for security and operational safety.
171+
172+
### Key Inherited Functionality:
173+
174+
- **ERC4626Upgradeable**: Used Openzeppelin's 4626 contract as base implementation of the ERC-4626 standard.
175+
- **AccessControlledV8**: Venus role-based access control system.
176+
- **ReentrancyGuardUpgradeable**: Protection against reentrancy attacks.
177+
- **MaxLoopsLimitHelper**: Prevents gas exhaustion in loops.
178+
179+
### Events
180+
181+
- **`ClaimRewards (event)`**: Emitted when rewards are claimed and distributed.
182+
- **`RewardRecipientUpdated (event)`**: Emitted when the reward recipient address is updated.
183+
- **`SweepToken (event)`**: Emitted when ERC-20 tokens are swept from the contract.
184+
185+
### State variables
186+
187+
- **`vToken (VToken)`**: The underlying Venus vToken being wrapped.
188+
- **`comptroller (IComptroller)`**: The Comptroller contract associated with the vToken.
189+
- **`rewardRecipient (address)`**: Address designated to receive reward tokens.
190+
191+
### Functions
192+
193+
#### Core ERC-4626 Functions
194+
195+
- **`deposit(uint256 assets, address receiver)`**: Deposits assets and mints shares to the receiver.
196+
- **`mint(uint256 shares, address receiver)`**: Mints exact shares by depositing required assets.
197+
- **`withdraw(uint256 assets, address receiver, address owner)`**: Withdraws exact assets and burns shares from the owner.
198+
- **`redeem(uint256 shares, address receiver, address owner)`**: Redeems exact shares and transfers assets to the receiver.
199+
- **`totalAssets()`**: Returns the total underlying assets held by the vault.
200+
201+
#### Initialization
202+
203+
- **`initialize(address vToken_)`**: Initializes the vault with the target vToken (first-stage init).
204+
- **`initialize2(address accessControlManager_, address rewardRecipient_, uint256 loopsLimit_)`**: Second-stage initialization with access control, reward recipient, and loop limit.
205+
206+
#### Reward Management
207+
208+
- **`claimRewards()`**: Claims all available rewards and sends them to the recipient.
209+
- **`setRewardRecipient(address newRecipient)`**: Updates the reward recipient address (ACM-restricted).
210+
211+
#### Admin Functions
212+
213+
- **`sweepToken(IERC20Upgradeable token)`**: Allows the owner to recover any ERC-20 tokens mistakenly sent to the vault.
214+
- **`setMaxLoopsLimit(uint256 loopsLimit)`**: Configures the maximum loop iterations (ACM-restricted).
215+
216+
### Error Codes
217+
218+
- **`VenusError(uint256 errorCode)`**: Generic error returned from Venus protocol operations.
219+
- **`ERC4626__ZeroAmount(string operation)`**: Thrown when a zero amount is provided during an operation.
220+
- **`ERC4626__DepositMoreThanMax()`**: Error triggered when a deposit exceeds the maximum limit.
221+
- **`ERC4626__MintMoreThanMax()`**: Error triggered when a mint exceeds the maximum limit.
222+
- **`ERC4626__WithdrawMoreThanMax()`**: Error triggered when a withdrawal exceeds the maximum limit.
223+
- **`ERC4626__RedeemMoreThanMax()`**: Error triggered when a redeem exceeds the maximum limit.
224+
225+
### **Deposit Flow**
226+
227+
```jsx
228+
function deposit(uint256 assets, address receiver)
229+
public
230+
override
231+
nonReentrant
232+
returns (uint256)
233+
{
234+
// Input validation
235+
if (assets == 0) revert ERC4626__ZeroAmount("deposit");
236+
if (assets > maxDeposit(receiver)) revert ERC4626__DepositMoreThanMax();
237+
238+
// Process deposit
239+
uint256 shares = previewDeposit(assets);
240+
_deposit(_msgSender(), receiver, assets, shares);
241+
242+
return shares;
243+
}
244+
```
245+
246+
1. Validates input parameters
247+
2. Calculates shares to mint
248+
3. Transfers assets from user
249+
4. Mints vTokens via Venus Protocol
250+
5. Issues vault shares to receiver
251+
252+
#### Example
253+
254+
**Scenario**: Alice deposits 100 USDC
255+
256+
<figure><img src="../../.gitbook/assets/erc4626-deposit.png" alt="Flow of funds related to Prime"><figcaption></figcaption></figure>
257+
258+
#### Result:
259+
260+
- Alice gets 100 vault shares
261+
- Vault holds 100 vUSDC (earning yield)
262+
263+
### **Withdrawal Flow**
264+
265+
```jsx
266+
function withdraw(uint256 assets, address receiver, address owner)
267+
public
268+
override
269+
nonReentrant
270+
returns (uint256)
271+
{
272+
// Input validation
273+
if (assets == 0) revert ERC4626__ZeroAmount("withdraw");
274+
if (assets > maxWithdraw(owner)) revert ERC4626__WithdrawMoreThanMax();
275+
276+
// Process withdrawal
277+
uint256 shares = previewWithdraw(assets);
278+
beforeWithdraw(assets); // Redeems from Venus
279+
_withdraw(_msgSender(), receiver, owner, assets, shares);
280+
281+
return shares;
282+
}
283+
```
284+
285+
1. Validates input parameters
286+
2. Calculates shares to burn
287+
3. Redeems underlying assets from Venus
288+
4. Transfers assets to receiver
289+
5. Burns vault shares
290+
291+
#### Example
292+
293+
#### Scenario: Alice withdraws 50 USDC (after interest accrual)
294+
295+
<figure><img src="../../.gitbook/assets/erc4626-withdraw.png" alt="Flow of funds related to Prime"><figcaption></figcaption></figure>
296+
297+
#### Result
298+
299+
Alice receives 50 USDC
300+
301+
- Vault burns shares adjusted for interest (e.g., 48.54 shares at 1.03 exchange rate)
302+
303+
### **Security Features**
304+
305+
1. **Reentrancy Protection**:
306+
307+
- All state-changing functions use **nonReentrant** modifier
308+
- Critical Venus operations (mint/redeem) are atomic
309+
310+
2. **Input Validation**:
311+
312+
- Zero-address checks via **ensureNonzeroAddress**
313+
- Zero-amount validation for all operations
314+
- Explicit error codes for Venus operations
315+
316+
3. **Access Control**:
317+
318+
- Sensitive functions protected by Venus's ACM
319+
- Reward recipient can only be changed by authorized accounts
320+
321+
---

0 commit comments

Comments
 (0)