We often encounter situations where a client wants to aggregate yields from different DeFi protocols but hits a zoo of incompatible interfaces. Before ERC-4626, each yield vault implemented its own interface: Yearn V2 had pricePerShare(), Compound used exchangeRate(), Aave worked through aToken with rebasing. Writing an aggregator working with multiple vaults simultaneously meant maintaining a zoo of adapters. ERC-4626 standardized this: one interface for all tokenized vaults. Now this standard is used by Yearn V3, Morpho Blue, most liquid staking protocols, and all major lending aggregators. It is the de facto standard for yield-bearing tokens. Whether you need a custom Solidity vault or a DeFi vault aggregating yields, we have the expertise. Order turnkey vault development—save time on integration and audits. With 5+ years of experience and over 30 DeFi projects delivered, we ensure high-quality solutions.
ERC-4626 is an extension of ERC-20 with methods for depositing/withdrawing assets (underlying asset), minting/redeeming shares (vault token), and conversion between assets and shares. It creates a tokenized vault for yield-bearing tokens. The vault token (shares) is a regular ERC-20 that can be traded and transferred. The share price increases as yield accrues. This fundamentally differs from rebasing (stETH), where the token balance changes while the price remains constant.
Vault Math: Price Per Share
The price per share in ERC-4626 is: pricePerShare = totalAssets / totalShares.
| Scenario | Formula for shares | Special Consideration |
|---|---|---|
| First deposit | shares = assets | Requires initialization with virtual shares |
| Subsequent deposits | shares = assets * totalShares / totalAssets | Round down |
| Withdrawal | assets = shares * totalAssets / totalShares | Round up |
On the first deposit (totalShares = 0), any formula dividing by zero is invalid. OpenZeppelin solves this by using virtual shares: initialize totalShares = 10^decimals, totalAssets = 10^decimals, giving an initial pricePerShare = 1. See OpenZeppelin ERC4626 documentation.
Inflation Attack on a Vault
This is a real vulnerability that allows the first depositor to profit at the expense of subsequent depositors. Scenario: an attacker deposits 1 wei, receives 1 share, then donates a large amount of the asset (bypassing deposit), sharply increasing the pricePerShare. The next user deposits 1000 USDC but, due to rounding down, receives 0 shares—their assets go to the attacker.
How to Protect Against an Inflation Attack
OpenZeppelin's ERC4626 (v5.0+) protects via virtual shares with _decimalsOffset(). Setting offset=3 creates a virtual reserve of 10^(3+decimals) shares against 10^decimals assets. The attacker would need to deposit an enormous sum for minimal gain—the attack becomes economically infeasible.
function _decimalsOffset() internal view virtual returns (uint8) {
return 0; // Increase to 3 for additional protection
}
Implementing a Basic ERC-4626 Vault
We use Foundry, Solidity 0.8.24, OpenZeppelin. The key point: the vault overrides totalAssets() to account not only for the vault's balance but also assets deployed in a strategy. Hooks _afterDeposit and _beforeWithdraw manage deployment and retrieval of funds.
View Full Vault Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract SimpleYieldVault is ERC4626, Ownable {
address public strategy;
uint256 public performanceFee; // 500 = 5%
constructor(
IERC20 asset_,
string memory name_,
string memory symbol_
) ERC4626(asset_) ERC20(name_, symbol_) Ownable(msg.sender) {}
function totalAssets() public view virtual override returns (uint256) {
uint256 vaultBalance = IERC20(asset()).balanceOf(address(this));
uint256 strategyBalance = strategy != address(0)
? IStrategy(strategy).totalAssets()
: 0;
return vaultBalance + strategyBalance;
}
function _afterDeposit(uint256 assets, uint256) internal virtual {
if (strategy != address(0)) {
IERC20(asset()).approve(strategy, assets);
IStrategy(strategy).invest(assets);
}
}
function _beforeWithdraw(uint256 assets, uint256) internal virtual {
uint256 vaultBalance = IERC20(asset()).balanceOf(address(this));
if (assets > vaultBalance && strategy != address(0)) {
IStrategy(strategy).divest(assets - vaultBalance);
}
}
}
Why Are Rounding Directions Important?
ERC-4626 explicitly specifies rounding: convertToShares and previewDeposit round down (floor), previewWithdraw rounds up (ceil), previewRedeem rounds down. Violating this is an audit finding. Rounding always favors the vault; otherwise, a drain through many small operations is possible.
Important Edge Cases
If the underlying asset is a fee-on-transfer token, the vault receives less than specified. Solution: measure the actual balance after transfer and recalculate shares. This is accounted for in the code.
Comparison of Yield Token Standards
| Standard | Type | Integration Ease | Manipulation Risk |
|---|---|---|---|
| ERC-4626 | Share-based | High (2-3x better than custom) | Low (inflation attack protection) |
| Rebasing | Balance-changing | Medium | Medium (aggregation complexity) |
| Custom | Various | Low | High (no unified interface) |
ERC-4626 is 2-3 times better for integrations than custom or rebasing solutions. This is confirmed by practice: many protocols are migrating to this standard, reducing development and audit costs.
Testing and Audit
We use the official property tests: ERC4626 Properties. Foundry fuzz tests cover roundtrip properties and invariants. We ensure your ERC-4626 audit covers all vulnerabilities, including the inflation attack vault scenario.
function testFuzz_DepositRedeem(uint256 assets) public {
assets = bound(assets, 1, 1e30);
vm.assume(assets <= token.balanceOf(user));
uint256 shares = vault.deposit(assets, user);
uint256 assetsBack = vault.redeem(shares, user, user);
// Rounding loss is at most 1 wei
assertApproxEqAbs(assetsBack, assets, 1);
}
We guarantee passing external audits: contracts pass Slither, Mythril, Echidna. Get a consultation on audit readiness. Typical audit costs range from $2,000 to $5,000 depending on complexity.
What's Included in ERC-4626 Vault Development
- Requirements analysis — discuss yield strategy, fee model, target network (Ethereum, Polygon, Arbitrum, etc.).
- Architecture design — interaction scheme of vault, strategies, harvester.
- Smart contract implementation — Solidity 0.8.x, Foundry, OpenZeppelin.
- Testing — unit, fuzz, integration tests (coverage >95%).
- Deployment and verification on Etherscan.
- Support during external audit — consultations and revisions.
- Technical documentation — contract descriptions, call flows.
Over 5 years, we have delivered more than 30 DeFi projects, including vault solutions for protocols with TVL over $100M. This allows us to anticipate typical problems and give architectural recommendations.
Timelines and Cost
Basic ERC-4626 vault with one strategy: 3-5 business days, starting from $5,000. Full vault with harvester, fee mechanism, and multiple strategies: 2-3 weeks, starting from $15,000. Save up to $10,000 on development costs compared to building from scratch with custom interfaces.
Our smart contract development for tokenized liquidity pools and tokenization of yield strategies ensures a robust ERC-4626 vault that passes all security checks.
Contact us to evaluate your project—we will select the optimal architecture. Order turnkey vault development and get a working contract with a ready-made test base.
Get a consultation on your project—our engineers will help choose the optimal strategy and reduce risks.







