npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@prime-vaults/contract

v0.1.0

Published

**PrimeVaults** is an enterprise-grade DeFi vault infrastructure built on the BoringVault architecture. It provides a secure, flexible, and composable framework for managing yield strategies with single-asset architecture.

Readme

PrimeVaults Smart Contracts

PrimeVaults is an enterprise-grade DeFi vault infrastructure built on the BoringVault architecture. It provides a secure, flexible, and composable framework for managing yield strategies with single-asset architecture.

📖 Table of Contents


🔍 Overview

PrimeVaults implements a single-asset vault model where each vault supports exactly one ERC20 token. This design simplifies security, reduces complexity, and eliminates MEV opportunities associated with multi-asset vaults.

Key Features

Single-Asset Architecture: One vault = one token, eliminating complex asset swapping logic
Modular Design: Minimal core vault contract (~100 lines) with logic delegated to external modules
Yield Streaming: Time-weighted yield distribution with TWAS (Time-Weighted Average Supply) validation
Buffer Helpers: Automatic capital deployment to yield strategies
Role-Based Security: Granular permission system via RolesAuthority
Transfer Hooks: Customizable share transfer restrictions for compliance
Non-Custodial: User funds secured in audited smart contracts


🏗 Architecture

PrimeVaults follows the BoringVault architecture pattern with these core components:

┌─────────────────────────────────────────────────────────────────┐
│                         USER LAYER                               │
│              (Deposits/Withdraws via Teller)                     │
└──────────────────────────┬──────────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│                    TELLER CONTRACT                               │
│  • Handles user deposits & withdrawals                           │
│  • Enforces share lock periods                                   │
│  • Manages deposit caps                                          │
│  • Triggers buffer helper hooks                                  │
└──────────────────────────┬──────────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│                   BORINGVAULT (CORE)                             │
│  • Minimal vault contract (~100 lines)                           │
│  • Holds user assets                                             │
│  • Mints/burns vault shares                                      │
│  • Delegates strategy execution to Manager                       │
└──────────────────────────┬──────────────────────────────────────┘
                           │
           ┌───────────────┴───────────────┐
           │                               │
           ▼                               ▼
┌──────────────────────┐        ┌──────────────────────┐
│    ACCOUNTANT        │        │    BUFFER HELPER     │
│  • Exchange rate     │        │  • Auto-deploy       │
│  • Fee calculation   │        │    capital           │
│  • Yield streaming   │        │  • Strategy calls    │
│  • TWAS validation   │        │  • Yield optimization│
└──────────────────────┘        └──────────────────────┘
           │
           ▼
┌──────────────────────┐
│    MANAGER           │
│  (Future: Merkle     │
│   verification)      │
└──────────────────────┘

📦 Core Contracts

1. BoringVault

The foundation of the vault system

  • Purpose: Minimal vault contract that holds user assets and delegates complex logic
  • Size: ~16 KB (100 lines of core logic)
  • Key Functions:
    • enter(): Mints vault shares in exchange for assets
    • exit(): Burns vault shares and returns assets
    • manage(): Executes strategy calls (restricted to authorized managers)
    • setBeforeTransferHook(): Configures transfer restrictions

Authorization: Requires MINTER_ROLE for deposits, BURNER_ROLE for withdrawals


2. Teller

User-facing deposit/withdrawal interface

  • Purpose: Facilitates user interactions with the vault
  • Size: ~18 KB
  • Key Features:
    • Single asset support
    • Share lock periods to prevent flashloan attacks
    • Deposit caps for risk management
    • Permit-based deposits (gasless approvals)
    • Deny lists and permissioned transfers for compliance

State Management:

struct TellerState {
  bool isPaused; // Emergency pause
  bool allowDeposits; // Toggle deposits
  bool allowWithdraws; // Toggle withdrawals
  bool permissionedTransfers; // Require whitelisting
  uint64 shareLockPeriod; // Minimum holding period
  uint112 depositCap; // Maximum total shares
}

Key Functions:

  • deposit(): Public deposits with optional native ETH
  • depositWithPermit(): Gasless approval deposits
  • withdraw(): Burns shares for underlying assets
  • bulkDeposit(): Authorized batch deposits
  • bulkWithdraw(): Authorized batch withdrawals

3. TellerWithBuffer

Automatic capital deployment layer

  • Purpose: Integrates buffer helpers to automate yield strategy allocation
  • Size: ~20 KB
  • How It Works:
    1. User deposits → Teller receives assets
    2. _afterDeposit() hook triggers → Buffer helper generates strategy calls
    3. Vault executes manage() calls → Assets deployed to yield protocols
    4. On withdrawal: _beforeWithdraw() → Buffer helper unwinds positions

Buffer Helper Interface:

struct BufferHelpers {
  IBufferHelper depositBufferHelper; // Deploy capital after deposits
  IBufferHelper withdrawBufferHelper; // Unwind positions before withdrawals
}

Example: PrimeStrategyV1BufferHelper automatically deposits assets into a strategy manager contract.


4. AccountantProviders

Exchange rate and fee management

  • Purpose: Provides share pricing and fee accounting
  • Size: ~12 KB
  • Core Responsibilities:
    • Maintains exchange rate (vault shares → underlying assets)
    • Calculates platform fees based on time and assets
    • Manages fee accrual and distribution
    • Pauses vault if needed
    • Updates exchange rate to reflect fees owed

State Structure:

struct AccountantState {
  address payoutAddress; // Where fees are sent
  uint128 feesOwedInBase; // Pending fee amount
  uint128 totalSharesLastUpdate; // Share supply snapshot
  uint96 exchangeRate; // Current rate (starts at 1:1)
  uint64 lastUpdateTimestamp; // Last update time
  bool isPaused; // Pause state
  uint16 platformFee; // Annual platform fee (bps)
}

Fee Calculation:

  • Platform Fee: (assets * platformFee * timeDelta) / (1e4 * 365 days)
  • Performance Fee: (yieldEarned * performanceFee) / 1e4

6. AccountantWithYieldStreaming

Advanced yield distribution with TWAS validation

  • Purpose: Streams yield over time instead of instant distribution
  • Size: ~18 KB
  • Key Concepts:
    • Vesting: Yield is distributed linearly over a period (1-7 days default)
    • TWAS: Time-Weighted Average Supply prevents manipulation
    • Anti-Manipulation: Requires yield vests to be within deviation bounds

Vesting Flow:

  1. Strategist calls vestYield(amount, duration)
  2. Contract validates:
    • Duration within bounds (1-7 days)
    • Yield not too large vs. TWAS
    • Minimum update delay respected
  3. Yield streams into exchange rate over vesting period

State Tracking:

struct VestingState {
  uint128 lastSharePrice; // Previous exchange rate
  uint128 vestingGains; // Remaining yield to vest
  uint128 lastVestingUpdate; // Last vest update time
  uint64 startVestingTime; // Vest period start
  uint64 endVestingTime; // Vest period end
}

struct SupplyObservation {
  uint256 cumulativeSupply; // ∫ totalSupply dt
  uint256 cumulativeSupplyLast; // Previous cumulative
  uint256 lastUpdateTimestamp; // Observation timestamp
}

7. RolesAuthority

Permission management system

  • Purpose: Implements role-based access control (RBAC)
  • Size: ~6 KB
  • Capabilities:
    • setRoleCapability(): Grant role X permission to call function Y on contract Z
    • setPublicCapability(): Make function publicly callable
    • setUserRole(): Assign role to address

Role Definitions:

uint8 constant MINTER_ROLE = 1; // Can mint vault shares
uint8 constant ADMIN_ROLE = 1; // Admin permissions
uint8 constant BORING_VAULT_ROLE = 4; // Vault contract itself
uint8 constant UPDATE_EXCHANGE_RATE_ROLE = 3; // Can update prices
uint8 constant STRATEGIST_ROLE = 7; // Can vest yield
uint8 constant BURNER_ROLE = 8; // Can burn shares
uint8 constant SOLVER_ROLE = 9; // Bulk operations

8. DelayedWithdraw

Secure delayed withdrawal system

  • Purpose: Implements delayed withdrawal mechanism with configurable waiting periods
  • Size: TBD
  • Key Features:
    • Delayed withdrawal requests (configurable delay period)
    • Completion window to prevent indefinite pending requests
    • Withdrawal fees support
    • Third-party completion option
    • Exchange rate locked at request time (no rewards after request)
    • Admin controls for emergency situations

State Management:

struct WithdrawAsset {
  bool allowWithdraws; // Toggle withdrawals
  uint32 withdrawDelay; // Delay before completion (e.g., 7 days)
  uint128 outstandingShares; // Total pending withdrawal shares
  uint16 withdrawFee; // Fee in basis points
}

struct WithdrawRequest {
  bool allowThirdPartyToComplete; // Allow others to complete
  uint40 maturity; // When withdrawal can be completed
  uint96 shares; // Shares to withdraw
  uint96 exchangeRateAtTimeOfRequest; // Locked exchange rate
}

Withdrawal Flow:

  1. Request: User calls requestWithdraw() → Shares transferred to contract, exchange rate locked
  2. Wait Period: Must wait for withdrawDelay seconds (e.g., 7 days)
  3. Complete: User calls completeWithdraw() anytime after maturity → Receives assets at locked rate (minus fees)
  4. Cancel: User can cancel anytime before completion to get shares back

Key Functions:

  • requestWithdraw(): Initiate withdrawal request
  • completeWithdraw(): Complete matured withdrawal
  • cancelWithdraw(): Cancel pending withdrawal
  • setupWithdrawAsset(): Admin setup for supported asset
  • cancelUserWithdraw(): Admin emergency cancel
  • completeUserWithdraw(): Admin force complete

Important: Once withdrawal is requested, shares are locked and no longer earn yield. The exchange rate is frozen at the time of request.


9. PrimeVaultFactory

Deployment configuration helper

  • Purpose: Configures role permissions for deployed vault systems
  • Size: ~6 KB (reference-only, no deployment)
  • Key Function: setup() assigns all roles and capabilities in one transaction

Setup Process:

function setup(
  RolesAuthority rolesAuthority,
  BoringVault boringVault,
  AccountantWithYieldStreaming accountant,
  TellerWithYieldStreaming teller
) external onlyOwner {
  // 1. Configure function permissions
  rolesAuthority.setRoleCapability(MINTER_ROLE, vault, vault.enter.selector, true);

  // 2. Make user functions public
  rolesAuthority.setPublicCapability(teller, teller.deposit.selector, true);

  // 3. Assign roles to contracts
  rolesAuthority.setUserRole(teller, MINTER_ROLE, true);
}

💰 Flow of Funds

Deposit Flow

1. User → Teller.deposit(1000 USDC)
   ├─ Teller checks: not paused, deposits allowed
   ├─ Teller transfers 1000 USDC from user
   └─ Teller calculates shares = amount * ONE_SHARE / exchangeRate

2. Teller → Vault.enter(user, USDC, 1000, user, shares)
   ├─ Vault mints 950 shares to user
   └─ Emits Enter event

3. Teller → _afterDeposit(1000)
   ├─ BufferHelper generates strategy calls
   ├─ Vault.manage([strategyManager], [deposit(1000)], [0])
   └─ 1000 USDC deployed to yield strategy

4. Share Lock Applied
   └─ Shares locked to user address for shareLockPeriod (prevents MEV)

Withdrawal Flow

1. User → Teller.withdraw(950 shares)
   ├─ Teller checks: not paused, withdrawals allowed
   └─ Teller verifies share lock period expired

2. Teller → _beforeWithdraw(1050)
   ├─ BufferHelper calculates assets needed
   ├─ Vault.manage([strategyManager], [withdraw(1050)], [0])
   └─ 1050 USDC withdrawn from strategy

3. Teller → Vault.exit(user, USDC, 1050, user, 950)
   ├─ Vault burns 950 shares from user
   ├─ Vault transfers 1050 USDC to user
   └─ Emits Exit event (user gained 50 USDC yield)

Yield Update Flow

1. Strategist → Accountant.vestYield(5000 USDC, 3 days)
   ├─ Validates: duration bounds, TWAS deviation
   ├─ Updates vesting state:
   │  └─ vestingGains = 5000
   │  └─ endVestingTime = now + 3 days
   └─ Emits YieldRecorded event

2. Oracle → Accountant.updateExchangeRate() [every 24h]
   ├─ Calculates vested yield: (5000 * elapsed) / 3 days
   ├─ Updates exchange rate: oldRate + (vestedYield / totalShares)
   ├─ Calculates platform fees
   └─ Updates state

3. Vault → Accountant.claimFees()
   ├─ Transfers accumulated fees to payoutAddress
   └─ Resets feesOwedInBase to 0

🔐 Role-Based Access Control

Permission Matrix

| Function | Role Required | Contract | | ------------------------- | ------------------------- | ------------------- | | deposit() | PUBLIC | Teller | | depositWithPermit() | PUBLIC | Teller | | withdraw() | PUBLIC | Teller | | bulkDeposit() | SOLVER_ROLE | Teller | | bulkWithdraw() | SOLVER_ROLE | Teller | | enter() | MINTER_ROLE | BoringVault | | exit() | BURNER_ROLE | BoringVault | | manage() | MANAGER_ROLE | BoringVault | | updateExchangeRate() | UPDATE_EXCHANGE_RATE_ROLE | AccountantProviders | | claimFees() | BORING_VAULT_ROLE | AccountantProviders | | pause() | ADMIN_ROLE | Teller/Accountant | | setBeforeTransferHook() | OWNER | BoringVault |

Role Assignment

// Teller can mint and burn vault shares
rolesAuthority.setUserRole(teller, MINTER_ROLE, true);
rolesAuthority.setUserRole(teller, BURNER_ROLE, true);

// Accountant can update rates and claim fees
rolesAuthority.setUserRole(accountant, UPDATE_EXCHANGE_RATE_ROLE, true);
rolesAuthority.setUserRole(accountant, STRATEGIST_ROLE, true);

// Vault contract can claim its own fees
rolesAuthority.setUserRole(vault, BORING_VAULT_ROLE, true);

📁 Contract Structure

contracts/
├── core/
│   ├── BoringVault.sol                    # Minimal vault core (~16 KB)
│   ├── Teller.sol                         # Base teller (~18 KB)
│   ├── TellerWithBuffer.sol               # Buffer integration (~20 KB)
│   ├── AccountantProviders.sol            # Exchange rate manager (~12 KB)
│   ├── DelayedWithdraw.sol                # Delayed withdrawal system
│   ├── Distributor.sol                    # Reward distribution
│   └── PrimeRegistry.sol                  # Registry and RBAC setup
│
├── auth/
│   ├── PrimeAuth.sol                      # Base auth contract
│   ├── PrimeRBAC.sol                      # RBAC implementation
│   └── RolesAuthority.sol                 # Role authority (~6 KB)
│
├── helper/
│   ├── MockERC20.sol                      # Testing token
│   └── PrimeBufferHelper.sol              # Buffer helper (~5 KB)
│
└── interfaces/
    ├── IBufferHelper.sol                  # Buffer helper interface
    ├── IBaseVault.sol                     # Vault interface
    └── hooks/
        └── IBeforeUpdateHook.sol          # Transfer hook interface

ignition/modules/                          # Hardhat Ignition deployment
├── vault/
│   ├── Vault.ts                           # Deploy BoringVault
│   ├── Accountant.ts                      # Deploy AccountantProviders
│   ├── Teller.ts                          # Deploy TellerWithBuffer
│   └── TellerHelper.ts                    # Deploy PrimeBufferHelper
├── PrimeRegistry.ts                       # Deploy PrimeRegistry
└── Distributor.ts                         # Deploy Distributor

test/
└── Staking.ts                             # Integration tests

🛠 Development

Prerequisites

  • Node.js >= 18.16.0
  • pnpm

Installation

# Clone repository
git clone https://github.com/Beraji-Labs/prime-vaults-contract.git
cd prime-vaults-contract

# Install dependencies
pnpm install

# Copy environment file
cp .env.example .env
# Edit .env with your configuration

Commands

# Compile contracts
pnpm compile

# Run tests
pnpm test

# Deploy to localhost (requires hardhat node running)
pnpm test-local

# Check contract sizes
pnpm contract-size

# Lint Solidity
pnpm lint:sol

# Lint TypeScript
pnpm lint:ts

# Fix linting issues
pnpm lint:fix

# Clean artifacts
pnpm clean

Deployment

# Start local Hardhat node
pnpm hardhat node

# Deploy to localhost
pnpm run deploy --network localhost -f 00 # MockERC20
pnpm run deploy --network localhost -f 01 # RolesAuthority
pnpm run deploy --network localhost -f 02 # Vault + Accountant
pnpm run deploy --network localhost -f 03 # Teller

Contract Sizes

All contracts are under the 24 KB Ethereum contract size limit:

| Contract | Size | % of Limit | | ------------------- | -------- | ---------- | | TellerWithBuffer | 20.54 KB | 83.5% | | Teller | 18.32 KB | 74.4% | | BoringVault | 15.99 KB | 65.0% | | AccountantProviders | 11.92 KB | 48.5% | | Distributor | ~10 KB | ~40% | | DelayedWithdraw | ~8 KB | ~33% | | PrimeRegistry | ~6 KB | ~25% | | RolesAuthority | 5.73 KB | 23.3% |


🔒 Security

Security Features

  1. Minimal Attack Surface: Core vault contract is only ~100 lines
  2. Role-Based Access: Granular permissions prevent unauthorized actions
  3. Share Lock Periods: Prevents flashloan attacks and MEV
  4. Pausability: Emergency pause functionality for Teller and Accountant
  5. Reentrancy Protection: All external calls use ReentrancyGuard
  6. Fee Management: Platform fees tracked and claimed separately
  7. Merkle Verification: Manager actions verified through Merkle proofs
  8. Transfer Hooks: Custom transfer restrictions for compliance

Architecture Benefits

  • Separation of Concerns: Strategy logic isolated from core vault
  • Upgradeability: External modules can be replaced without touching vault
  • Auditability: Each component is independently auditable
  • Composability: Vault shares can be used in other DeFi protocols

Audits

Audits pending


📚 Additional Resources

  • Veda Documentation: https://docs.veda.tech/
  • BoringVault Architecture: https://docs.veda.tech/architecture-and-flow-of-funds
  • Original BoringVault: https://github.com/Veda-Labs/boring-vault

📄 License

This project is licensed under MIT.


👥 Authors

PrimeVaults Team
© 2025 PrimeVaults

Built with ❤️ using Hardhat, Viem, and Solidity ^0.8.30