Skip to content

ProvLabs/nuva-evm-contracts

Repository files navigation

Nuva EVM Contracts

This repository is a Hardhat-based Solidity monorepo for the Nuva protocol. It contains two largely independent product surfaces plus shared infrastructure:

  • Cross-Chain Token System (contracts/): An ERC20 (CustomToken) bridged across chains via Wormhole/Circle CCTP (CrossChainVault, CrossChainManager, RemoteVault), with a PriceOracle and a GovernanceTimelock.
  • Prime Vault Stack (contracts/prime/): A UX-focused ERC4626 staking product comprising DedicatedVaultRouter, NuvaVault, and RedemptionProxy.
  • Shared Modules (contracts/modules/): EIP-3009 transfer-with-authorization, Wormhole/CCTP interfaces, and byte/token utilities.

Tech Stack

  • Language: Solidity ^0.8.20 (compilers 0.8.20 and 0.8.28, both with viaIR and optimizer runs: 200).
  • Framework: Hardhat 2.26.3 with hardhat-toolbox and @openzeppelin/hardhat-upgrades.
  • Libraries: OpenZeppelin Contracts & Contracts-Upgradeable 5.4.0, Wormhole SDK.
  • Networks: sepolia (chainId 11155111) and baseSepolia (chainId 84532); upgrade manifests live in .openzeppelin/.

Contracts Overview

Core Contracts

  • CustomToken: An ERC20 token with additional features like minting, burning, and permit functionality.
  • CrossChainVault: Cross-chain token bridge using Wormhole infrastructure.
  • CrossChainManager: AML-compliant cross-chain token management system.
  • GovernanceTimelock: Time-delayed multisig or DAO executor for secure protocol changes.
  • RemoteVault: AML-compliant remote vault token management system (Vault V2).
  • PriceOracle: Price oracle for nvTokens.

Prime Vault Stack

  • DedicatedVaultRouter: UX-focused router for multi-hop ERC4626 vault deposits and asynchronous redemptions.
  • NuvaVault: Production ERC4626 vault with UUPS upgradeability, inflation-attack protection, and pausability.
  • RedemptionProxy: Disposable EIP-1167 minimal-proxy clone that isolates accounting for asynchronous redemptions.

Cross-Chain Contracts

Prime Vault Stack Documentation

Architecture & Design Patterns

A. Cross-Chain Token System

  • CustomToken (contracts/CustomToken.sol): UUPS-upgradeable ERC20 with ERC20Permit, EIP3009 (transfer-with-authorization), configurable decimals, and MINTER_ROLE-gated mint/burn. Access via AccessControlEnumerable + Ownable2Step.
  • CrossChainVault (contracts/CrossChainVault.sol): Sends tokens cross-chain using Circle CCTP v1 through a Wormhole executor (ICCTPv1WithExecutor). Gated by WHITELISTED_ROLE; emits TokensSent with Wormhole/Circle routing metadata.
  • CrossChainManager (contracts/CrossChainManager.sol): Orchestrates AML-verified deposits and burns, routes to destination chains via DestinationConfig, and integrates CustomToken + CrossChainVault. Uses BURN_ROLE/BURN_ADMIN_ROLE and ECDSA-based AML signature verification.
  • RemoteVault (contracts/RemoteVault.sol): AML-compliant deposit/withdraw vault (Vault V2) supporting both local and bridged modes, EIP-712 typed Deposit/Withdraw signatures, permit, and pausability.
  • PriceOracle (contracts/PriceOracle.sol): Stores a CoinGecko-trackable cgPricePerShare with a heartbeat staleness guard. PRICING_ROLE sets prices; ownership and role renouncement are disabled.
  • GovernanceTimelock (contracts/GovernanceTimelock.sol): Thin wrapper over OpenZeppelin TimelockController for delayed, multi-sig/DAO-governed execution.

B. Prime Vault Stack

1. Multi-Hop Deposit Flow

The DedicatedVaultRouter implements a three-layer staking flow:

  • Hop 1: Asset (e.g., USDC) -> assetVault shares.
  • Hop 2: assetVault shares -> stakingVault shares.
  • Hop 3: stakingVault shares -> nuvaVault shares.
  • Mechanism: Uses forceApprove + standard IERC4626.deposit, with per-hop slippage checks (SlippageExceeded) and FundsStuck invariants ensuring no residual balance remains in the router.
  • Entry points: depositUnchecked and depositWithPermitUnchecked are the active paths. The original AML-gated deposit/depositWithPermit (and their requestRedeem* counterparts) are deprecated — they ignore the amlSignature/amlDeadline args and emit FunctionDeprecatedWarning.

2. Asynchronous Redemptions (Disposable Proxies)

To isolate accounting and handle asynchronous lock periods, redemptions use EIP-1167 minimal-proxy clones of RedemptionProxy:

  • Request: User calls requestRedeemUnchecked (or permit variant) with a _deadline (≤ MAX_DEADLINE = 24h). The router clones RedemptionProxy, validates the clone's codehash against the expected EIP-1167 bytecode, escrows the user's Nuva shares, and records a UserFunds entry stamped with the current redemptionImplementationEpoch.
  • Accept / Reject: A keeper batch-processes requests via acceptRedeemRequests / rejectRedeemRequests. Each proxy is isolated through an external self-call (_doAcceptRedeemRequest / _doRejectRedeemRequest) so one failure cannot revert the batch (RedemptionAcceptFailed / RedemptionRejectFailed).
  • Unwind: On accept, the proxy unwinds Nuva -> staking -> asset shares and calls assetVault.requestRedeem (async lock).
  • Sweep: After the async period, the keeper calls sweepRedemptions to push assets from proxies back to users (RedemptionsSwept), deleting mappings only when a proxy is fully drained.
  • User safety valves: reclaimExpiredShares (router) lets a user recover escrowed shares after the deadline; rescueSweep and cancelRedemption (proxy) let the user recover funds/shares after a 7-day timeout.

3. Epoch-Based Implementation Freezing

setRedemptionProxyImplementation bumps redemptionImplementationEpoch. Pending requests stamped with a stale epoch are frozen (RedemptionFrozen): they can only be refunded via rejectRedeemRequests, never accepted. This prevents a newly configured proxy implementation from being applied retroactively to active positions.

4. NuvaVault (Production ERC4626)

  • Standards: ERC4626Upgradeable + ERC20PermitUpgradeable.
  • Upgradeability: UUPS, owner-authorized.
  • Inflation Protection: _decimalsOffset() of 12 to deter share-manipulation/donation attacks.
  • Pausability: PAUSER_ROLE can pause deposits/mints/withdrawals/redeems (max* return 0 while paused). ERC20 transfers remain enabled during pause to preserve secondary-market access.
  • Deprecated AML: depositWithPermit/redeemWithPermit AML variants are deprecated in favor of the *Unchecked variants.

C. Shared Modules (contracts/modules/)

  • eip-3009/: EIP3009, EIP712, ECRecover implementing transfer-with-authorization for CustomToken.
  • wormhole/: ICCTPv1WithExecutor plus ExecutorArgs/FeeArgs structs for CCTP relaying.
  • utils/: BytesLib (byte slicing) and ICustomToken interface.

Permissions & Access Control

  • Ownable2Step: "Heavy" administration — upgrades, setting the master RedemptionProxy implementation, managing roles. Ownership renouncement is disabled across contracts.
  • AccessControl(Enumerable): "Operational" roles.
    • KEEPER_ROLE (router): acceptRedeemRequests, rejectRedeemRequests, sweepRedemptions — intended for automated bot wallets.
    • PAUSER_ROLE (NuvaVault), MINTER_ROLE (CustomToken), PRICING_ROLE (PriceOracle), WHITELISTED_ROLE (CrossChainVault), BURN_ROLE/BURN_ADMIN_ROLE (CrossChainManager).
    • DEFAULT_ADMIN_ROLE: used only by contracts that explicitly grant it during initialization; Prime stack operational roles are managed through owner-only helper functions.

Prerequisites

  • Node.js (v16 or later)
  • npm or yarn
  • Hardhat

Installation

  1. Clone the repository:

    git clone <repository-url>
    cd nuva-evm-contracts
  2. Install dependencies:

    npm install
    # or
    yarn install

Testing

Run the test suite:

# Run all tests
npm test

# Run tests with gas reporting
REPORT_GAS=true npm test

# Run specific test file
npx hardhat test test/RemoteVault.js

# Run tests with detailed output
npx hardhat test --verbose

Development

Available Scripts

  • npm run lint: Check code style
  • npm run lint:fix: Automatically fix code style issues
  • npm run lint:solfix: Format Solidity code style
  • npm run lint:solcheck: Check Solidity code style
  • npx hardhat compile: Compile contracts
  • npx hardhat clean: Clean cache and artifacts
  • npx hardhat node: Start local Ethereum node
  • npx hardhat coverage: Generate test coverage report
  • npx hardhat verify --network sepolia <contract_address>: Verify contract on Etherscan

Verification Mandate

After any contract modification, run the verification suite:

npm run lint:solcheck                          # Solidity style check (lint:solfix to auto-format)
npm run lint                                   # JS/TS style check (lint:fix to auto-format)
npx hardhat compile                            # Compile
npx hardhat test                               # Full test suite
npx hardhat test test/DedicatedVaultRouter.js  # Single suite

CI (.github/workflows/ci.yml) runs compile + tests on push/PR to main and publishes a JUnit summary.

Professional Standards

  • NatSpec: All public/external functions, events, and state variables must have full @notice, @param, and @return tags.
  • Specific Imports: Avoid global imports. Use { Symbol } from "path".
  • Storage Safety: Maintain a uint256[N] private __gap in all upgradeable contracts, decremented as storage slots are consumed. Deprecated slots are preserved and renamed (__deprecated_* with @custom:oz-renamed-from) rather than removed, and existing gap sizes are kept to match prior deployments.
  • Initialization: Use _unchained initializers within initialize to prevent double-initialization across multiple inheritance, and disable initializers in the constructor (_disableInitializers()).
  • Safety patterns: nonReentrant on external state-changing flows, forceApprove for allowances, SafeERC20 for transfers, balance-delta invariants (FundsStuck) to detect fee-on-transfer/leftover funds, and per-item isolation via try/catch in keeper batch operations.

Security

This project includes security features such as:

  • Access control with OpenZeppelin's AccessControl and Ownable2Step
  • Reentrancy protection (ReentrancyGuard)
  • Input validation and balance-delta invariants
  • ERC4626 inflation-attack protection via _decimalsOffset()
  • Pausable emergency stops on vault operations
  • ECDSA/EIP-712 signature verification (AML paths retained for legacy cross-chain flows; deprecated in the Prime stack)

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

About

NUVA Finance EVM Vault Contracts

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors