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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@yieldxyz/shield

v1.7.0

Published

Zero-trust transaction validation library for Yield.xyz integrations.

Readme

🛡️ @yieldxyz/shield

CI npm version License: MIT

Zero-trust transaction validation for Yield.xyz integrations. Shield ensures every transaction is structurally correct and untampered before signing.

Installation

For TypeScript/JavaScript Projects

npm install @yieldxyz/shield

For Other Languages (Standalone Binary)

Download the pre-built binary for your platform from GitHub Releases:

| Platform | Download | | --------------------- | ------------------------ | | Linux (x64) | shield-linux-x64 | | macOS (Apple Silicon) | shield-darwin-arm64 | | macOS (Intel) | shield-darwin-x64 | | Windows | shield-windows-x64.exe |

# Example: Download for macOS Apple Silicon
curl -L https://github.com/stakekit/shield/releases/latest/download/shield-darwin-arm64 -o shield
chmod +x shield

# Verify integrity (recommended)
curl -LO https://github.com/stakekit/shield/releases/latest/download/shield-darwin-arm64.sha256
shasum -a 256 -c shield-darwin-arm64.sha256
# Expected output: shield-darwin-arm64: OK

See the examples/ directory for complete integration examples in Python, Go, and Rust.

Usage

import { Shield } from '@yieldxyz/shield';

const shield = new Shield();

// Parameters controlled by the caller. Keeping them in variables lets us
// use the same values for the request and, later, for validation.
const yieldId = 'ethereum-eth-lido-staking';
const userWalletAddress = '0x742d35cc6634c0532925a3b844bc9e7595f0beb8';
const args = { amount: '0.01' };

// Get transaction from Yield API
const response = await fetch('https://api.yield.xyz/v1/actions/enter', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': process.env.YIELD_API_KEY, // Your API key
  },
  body: JSON.stringify({
    yieldId,
    address: userWalletAddress,
    arguments: args,
  }),
});

const action = await response.json();

// Validate before signing.
//
// Note: only `transaction.unsignedTransaction` should come from the API
// response. The other fields — yieldId, userAddress, args — should be the
// values you sent in the request, since the goal is to check the API's
// transaction against what you actually asked for.
for (const transaction of action.transactions) {
  const result = shield.validate({
    unsignedTransaction: transaction.unsignedTransaction,
    yieldId,
    userAddress: userWalletAddress,
    args, // Optional
  });

  if (!result.isValid) {
    throw new Error(`Invalid transaction: ${result.reason}`);
  }
}

How It Works

Shield automatically detects and validates transaction types through pattern matching. Each transaction must match exactly one known pattern to be considered valid.

Using Shield from Other Languages

Shield is written in TypeScript, but can be used from any programming language via its CLI (Command Line Interface).

Why Two Approaches?

| Your Language | How to Use Shield | | ---------------------------------- | ------------------------------------------------- | | TypeScript/JavaScript | Import the library directly (see Usage) | | Python, Go, Ruby, Rust, Java, etc. | Use the CLI via subprocess |

The CLI approach means you get the exact same validation logic without rewriting Shield in your language.

The JSON Protocol

The CLI reads JSON from stdin and writes JSON to stdout:

Input:

{
  "apiVersion": "1.0",
  "operation": "validate",
  "yieldId": "ethereum-eth-lido-staking",
  "unsignedTransaction": "{\"to\":\"0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84\",...}",
  "userAddress": "0x742d35cc6634c0532925a3b844bc9e7595f0beb8"
}

Output:

{
  "ok": true,
  "apiVersion": "1.0",
  "result": {
    "isValid": true,
    "detectedType": "STAKE"
  },
  "meta": {
    "requestHash": "a1b2c3..."
  }
}

Operations

| Operation | Required Fields | Description | | ---------------------- | ----------------------------------------------- | ----------------------------- | | validate | yieldId, unsignedTransaction, userAddress | Validate a transaction | | isSupported | yieldId | Check if a yield is supported | | getSupportedYieldIds | (none) | List all supported yields |

CLI Examples (Bash)

# Check if a yield is supported
echo '{"apiVersion":"1.0","operation":"isSupported","yieldId":"ethereum-eth-lido-staking"}' | npx @yieldxyz/shield

# Validate a transaction
echo '{"apiVersion":"1.0","operation":"validate","yieldId":"ethereum-eth-lido-staking","unsignedTransaction":"{...}","userAddress":"0x..."}' | npx @yieldxyz/shield


# List supported yields
echo '{"apiVersion":"1.0","operation":"getSupportedYieldIds"}' | npx @yieldxyz/shield

Supported Yield IDs

  • ethereum-eth-lido-staking
  • solana-sol-native-multivalidator-staking
  • tron-trx-native-staking
  • All generic ERC4626 vault yields from: Angle, Curve, Euler, Fluid, Gearbox, Idle Finance, Lista, Morpho, Sky, SummerFi, Venus Flux, Yearn, Yo Protocol

To see the full list:

echo '{"apiVersion":"1.0","operation":"getSupportedYieldIds"}' | npx @yieldxyz/shield

Note: Aave, Maple, Spark use non-standard transaction flows and are not yet supported. Protocol-specific validators for these will be added in a future release.

ERC4626 Vault Operations

Shield validates the following operations for all supported ERC4626 vaults:

| Operation | Transaction Type | Description | | ----------- | ---------------- | --------------------------------------------- | | Approve | APPROVAL | ERC20 token approval for vault deposit | | Deposit | SUPPLY | Deposit assets into vault | | Mint | SUPPLY | Mint vault shares | | Withdraw | WITHDRAW | Withdraw assets from vault | | Redeem | WITHDRAW | Redeem vault shares | | WETH Wrap | WRAP | Convert native ETH to WETH (WETH vaults only) | | WETH Unwrap | UNWRAP | Convert WETH to native ETH (WETH vaults only) |

Amount intent (args) — ERC-4626 enter & exit

Amount checks are opt-in. If you omit args.amount / args.shareAmount, Shield runs only structural checks (vault whitelist, owner/receiver, method, non-zero).

Units: pass base-unit integer strings (wei) only — the same scale as calldata. Human values like "0.01" are rejected.

| Calldata | Pass to Shield | Match rule | | -------- | -------------- | ---------- | | deposit / approve / WRAP | args.amount (asset wei) | Exact | | withdraw(assets, …) | args.amount (asset wei) | Within 10 wei (monorepo near-max snap) | | redeem(shares, …) | args.shareAmount (share wei) | Within margin (see below) |

Do not declare both amount and shareAmount. Do not pass asset amount on a redeem, or shareAmount on a withdraw (fail-closed).

Match the built tx, not only what you sent the Yield API:

| Yield API exit | Typical calldata | Shield args | | -------------- | ---------------- | ----------- | | amount with withdraw-on-amount (team flag off) | withdraw(assets) | amount = asset wei | | shareAmount / shareAmountRaw | redeem(shares) | shareAmount = share wei | | useMaxAmount: true | redeem(maxRedeem) | shareAmount from balances shareAmountRaw, or omit intent |

// Partial exit — withdraw(assets)
shield.validate({
  unsignedTransaction,
  yieldId,
  userAddress,
  args: { amount: '1000000' }, // 1 USDC @ 6 decimals, wei
});

// Share exit — redeem(shares)
shield.validate({
  unsignedTransaction,
  yieldId,
  userAddress,
  args: { shareAmount: '1000000000000000000' }, // 1 share @ 18 decimals
});

// Full exit (useMaxAmount) — redeem; declare the share balance, not an asset amount
shield.validate({
  unsignedTransaction,
  yieldId,
  userAddress,
  args: { shareAmount: balance.shareAmountRaw },
});

Redeem margin

  • Default / underlying vault: "10" share wei.
  • Allocator / OAV target (tx.to in the registry's allocatorVaults): decimal-gap margin 10^(abs(inputDecimals − vaultDecimals) + 1) — e.g. USDC 6 vs shares 18 → 10^13 — except a small hardcoded set of OAVs that stay at "10" for parity with the Yield API exit path.

API Reference

shield.validate(request)

Validates a transaction by auto-detecting its type.

Parameters:

{
  unsignedTransaction: string;  // Transaction from Yield API
  yieldId: string;              // Yield integration ID
  userAddress: string;          // User's wallet address
  args?: ActionArguments;       // Optional arguments
  context?: ValidationContext;  // Trusted control-plane data (see Runtime OAV injection)
}

Returns:

{
  isValid: boolean;
  reason?: string;         // Why validation failed
  details?: any;          // Additional error details
  detectedType?: string;  // Auto-detected type (for debugging)
}

shield.isSupported(yieldId)

Check if a yield is supported.

shield.getSupportedYieldIds()

Get all supported yield IDs.

Error Messages

Common validation failures:

  • "Invalid referral address" - Wrong referral in transaction
  • "Withdrawal owner does not match user address" - Ownership mismatch
  • "Transaction validation failed: No matching operation pattern found" - Transaction doesn't match any supported pattern
  • "Transaction validation failed: Ambiguous transaction pattern detected" - Transaction matches multiple patterns

Security

Shield is designed with security as a top priority:

  • Input Validation: All inputs are validated against strict JSON schemas with size limits (100KB max)
  • Pattern Matching: Transactions must match exactly one known pattern to be valid
  • No Network Access: The CLI binary has no network capabilities - it only reads stdin and writes stdout
  • Checksum Verification: All release binaries include SHA256 checksums for integrity verification

Embedded Vault Registry

ERC-4626 vault data is embedded at build time from the installed package’s vault-registry.json (addresses, token decimals, and allocatorVaults). Transactions to known allocator vaults use the same ERC-4626 checks. Treat that snapshot as a baseline for third-party vaults, not as the decision gate for “is this project OAV already allowed?” The copy on GitHub main can lag the package you actually run, and both can lag newly deployed OAVs. Always pass your project’s OAVs in context (additive; see below). A registry re-export + publish is convenience for the static snapshot, not a prerequisite for validating a live OAV.

Runtime OAV injection (context)

For OAV-enabled ERC-4626 yields, pass project OAVs on every validate call. Injection is additive: it can unblock a legitimate OAV that is missing from the baked snapshot; it does not remove static-registry vaults.

shield.validate({
  unsignedTransaction,
  yieldId,
  userAddress,
  args, // optional
  context: {
    feeConfiguration: [
      {
        allocatorVaultAddress: '0x…', // OAV / allocator vault
        // Required for injected-OAV APPROVAL. Omit only if you are not
        // validating approvals against this OAV (supply/withdraw still pass).
        allocatorVaultInputTokenAddress: '0x…', // that OAV's underlying token
      },
    ],
  },
});

allocatorVaultInputTokenAddress is required for injected-OAV APPROVAL. Shield checks the approval token against this address. If it is omitted or does not match, APPROVAL is blocked. Supply and withdraw still succeed if you pass only allocatorVaultAddress. The token may differ from the yield’s base vault (e.g. a meta-vault).

Trust boundary: context is trusted control-plane data. Populate it server-side from the project’s own authenticated fee-configuration / OAV records. Never take it from the end user or from unsignedTransaction. User-supplied addresses in context expand the vault/spender whitelist and defeat Shield.

Shield stays offline; fetching OAVs is the caller’s job. Injection only widens that whitelist — from / owner / receiver, method, calldata, and amount checks still apply.

Verifying Binary Integrity

Always verify downloaded binaries:

# Download binary and checksum
curl -LO https://github.com/stakekit/shield/releases/latest/download/shield-darwin-arm64
curl -LO https://github.com/stakekit/shield/releases/latest/download/shield-darwin-arm64.sha256

# Verify
shasum -a 256 -c shield-darwin-arm64.sha256
# Expected: shield-darwin-arm64: OK

License

MIT