XSushiVault is an ERC4626-compliant tokenized vault, ensuring seamless integration with other DeFi protocols that support this standard. It allows users to deposit Sushi tokens, stake them in the SushiBar, and receive vault shares representing their stake. The zap functionality simplifies deposits by swapping supported tokens (e.g., USDC, WETH) for Sushi via Uniswap V3 in a single transaction. Security is prioritized with OpenZeppelin’s ReentrancyGuard and SafeERC20 for robust protection and safe token handling.
- ERC4626 Standard Compliance: Implements the ERC4626 tokenized vault standard for ease of integration with DeFi protocols.
- SushiBar Staking: Deposited Sushi is staked in the SushiBar, earning xSushi.
- Token Swapping / Zap Functionality: Users can deposit different tokens, which are swapped for Sushi before being staked.
- Secure & Optimized: Implements OpenZeppelin security best practices, including reentrancy protection and safe token transfers.
-
- Install NodeJS
-
Clone the repository:
git clone https://github.com/musti17/ERC-4626-Vault.git
-
Install dependencies:
npm install
-
Start a local Hardhat blockchain (forking mainnet to simulate mainnet conditions by providing blocknumber and rpc in hardhat.config.js):
npx hardhat node
-
For Running Smart Contract Tests
npx hardhat test tests/XSushiVault.test.js
The following decisions were made to balance security, gas efficiency, and functionality in XSushiVault:
-
Precise Approval Management
- Decision: Approved the exact amount of tokens needed for each operation while staking Sushi or unstaking xSushi rather than using infinite approvals.
- Reasoning: Infinite approvals could save ~20,000 gas per call by avoiding repeated approvals, but they pose a security risk—if the SushiBar or router is compromised, the vault’s tokens could be drained. Security is prioritized over gas savings in this DeFi context.
-
Hardcoded Swap Deadline in zapIn
- Decision: Used a fixed deadline of
block.timestamp + 1000
for swaps inzapIn
. - Reasoning: A user-defined deadline could avoid gas waste on delayed swaps, but the 1000-second buffer is practical and simplifies the implementation for now. The gas savings from a dynamic deadline are minimal.
- Decision: Used a fixed deadline of
-
Redundant Check in zapIn
- Decision: Included a
require(sushiReceived > 0)
check after swaps inzapIn
. - Reasoning: Although the SushiSwap router should revert on failed swaps, this check adds an extra safety layer against unexpected behavior, costing only ~200-300 gas. The security benefit justifies the small cost.
- Decision: Included a
-
Solidity Math Over Assembly
- Decision: Used
Math.ceilDiv
for calculations instead of inline assembly. - Reasoning: Assembly could save ~50-100 gas per operation but would reduce readability and increase error risk. Maintainability and simplicity are prioritized over minor gas optimizations.
- Decision: Used
-
Immutable Variables
- Decision: Declared key addresses (i.e.,
sushi
,sushiBar
,router
,xSushi
) as immutable. - Reasoning: Reduces storage costs and gas usage compared to regular storage variables, enhancing efficiency without compromising security.
- Decision: Declared key addresses (i.e.,
-
NatSpec Format for Documentation
- Decision: Adopted Solidity's NatSpec format for writing function and contract-level documentation.
- Reasoning: Provides clear explanations for contract functions, making the codebase more maintainable and readable for developers and auditors.
-
Pinned Dependencies
- Decision: Locked dependency versions in
package.json
to ensure reproducibility and avoid breaking changes. - Reasoning: Helps prevent unexpected issues when deploying or testing the contract by keeping dependency versions fixed.
- Decision: Locked dependency versions in
-
Magic Strings Removed
- Decision: Replaced hardcoded string literals with constants where applicable.
- Reasoning: Improves code maintainability, reduces risk of typos, and makes future modifications easier.
These decisions ensure XSushiVault is secure, gas-efficient, and maintainable while adhering to the ERC4626 standard.
- Reentrancy Protection: All state-changing functions that interact with external contracts use nonReentrant, ensuring that reentrancy attacks (where an attacker repeatedly calls a function before the first call is completed) cannot occur.
- Use of SafeERC20: Ensures safe interactions with ERC20 tokens, preventing unexpected failures.
- Minimized External Calls: External calls (e.g., swaps, staking) are optimized to reduce gas costs and attack vectors.