{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "defi-staking-yield-vault",
  "title": "Defi Staking Yield Vault",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/defi-staking-yield-vault/defi-staking-yield-vault.component.ts",
      "content": "// Nodeka and Uniswap-inspired DeFi staking yield vault: wallet connection header with\n// audit + TVL badges, four staking performance KPI cards, a deposit & stake simulator\n// (token selector, amount input with presets + slider, lockup multipliers, live yield\n// estimates), and a yield vaults directory. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core'\nimport {\n  ArrowUpRight,\n  Check,\n  Coins,\n  Copy,\n  Flame,\n  Fuel,\n  Lock,\n  LucideAngularModule,\n  Percent,\n  RefreshCw,\n  ShieldAlert,\n  ShieldCheck,\n  TrendingUp,\n  Unlock,\n  Wallet,\n  Zap,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardFooterComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\nimport { UiSliderComponent } from '@/ui/slider/slider.component'\n\ninterface VaultTokenOption {\n  symbol: string\n  name: string\n  price: number\n  balance: number\n  apyBoost: number\n  description: string\n  iconColor: string\n}\n\nconst tokenOptions: VaultTokenOption[] = [\n  {\n    symbol: 'ETH',\n    name: 'Native Ether',\n    price: 3450.0,\n    balance: 32.5,\n    apyBoost: 0,\n    description: 'Base Layer Staking',\n    iconColor: '#627EEA',\n  },\n  {\n    symbol: 'stETH',\n    name: 'Lido Staked ETH',\n    price: 3450.0,\n    balance: 15.2,\n    apyBoost: 0,\n    description: '1:1 Rebase Token',\n    iconColor: '#00A3FF',\n  },\n  {\n    symbol: 'wstETH',\n    name: 'Wrapped stETH',\n    price: 4015.0,\n    balance: 8.4,\n    apyBoost: 0.15,\n    description: 'Compounding Value Token',\n    iconColor: '#0052FF',\n  },\n]\n\ninterface VaultLockupOption {\n  id: string\n  label: string\n  durationText: string\n  days: number\n  boost: number\n  badge: string\n}\n\nconst lockupOptions: VaultLockupOption[] = [\n  { id: 'flex', label: 'Flexible', durationText: '0-Day Lock', days: 0, boost: 0, badge: 'Flexible' },\n  { id: '30d', label: '30 Days', durationText: '30-Day Lock', days: 30, boost: 0.5, badge: '+0.5% APY' },\n  { id: '90d', label: '90 Days', durationText: '90-Day Lock', days: 90, boost: 1.2, badge: '+1.2% APY' },\n  { id: '365d', label: '365 Days', durationText: '365-Day Lock', days: 365, boost: 2.5, badge: '+2.5% APY' },\n]\n\ninterface VaultItem {\n  id: string\n  name: string\n  pairSymbol: string\n  protocol: string\n  apy: string\n  apyRaw: number\n  tvl: string\n  risk: 'Low Risk' | 'Medium Risk' | 'High Risk'\n  riskVariant: 'emerald' | 'amber' | 'rose'\n  strategy: string\n  metricLabel: string\n  metricValue: string\n  isCurrentVault?: boolean\n}\n\nconst yieldVaults: VaultItem[] = [\n  {\n    id: 'eth-usdc-lp',\n    name: 'ETH-USDC LP',\n    pairSymbol: 'ETH + USDC',\n    protocol: 'Uniswap v3 · Concentrated',\n    apy: '12.40%',\n    apyRaw: 12.4,\n    tvl: '$58,420,000.00',\n    risk: 'Medium Risk',\n    riskVariant: 'amber',\n    strategy: 'Automated Rebalancing Range ±5%',\n    metricLabel: '24h Volume',\n    metricValue: '$4.2M Vol',\n  },\n  {\n    id: 'liquid-staked-eth',\n    name: 'Liquid Staked ETH',\n    pairSymbol: 'ETH / stETH',\n    protocol: 'Lido & Distributed Validator',\n    apy: '7.42%',\n    apyRaw: 7.42,\n    tvl: '$142,850,000.00',\n    risk: 'Low Risk',\n    riskVariant: 'emerald',\n    strategy: 'Consensus Layer + MEV Boost',\n    metricLabel: 'Lockup Period',\n    metricValue: 'Instant 0-Day',\n    isCurrentVault: true,\n  },\n  {\n    id: 'stablecoin-vault',\n    name: 'Stablecoin Multi-Vault',\n    pairSymbol: 'USDC + USDT + DAI',\n    protocol: 'Curve & Morpho Blue Optimizer',\n    apy: '9.80%',\n    apyRaw: 9.8,\n    tvl: '$94,180,000.00',\n    risk: 'Low Risk',\n    riskVariant: 'emerald',\n    strategy: 'Multi-Asset Lending & Arbitrage Yield',\n    metricLabel: 'Coverage',\n    metricValue: 'Nexus Mutual Protected',\n  },\n]\n\nconst walletAddress = '0x71C856402244243b92834b9d09c2534575823a9F'\n\nfunction fmtUsd(v: number): string {\n  return v.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-defi-staking-yield-vault, [ui-defi-staking-yield-vault]',\n  standalone: true,\n  // React renders the root <div> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiCardDescriptionComponent,\n    UiCardFooterComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiInputComponent,\n    UiSeparatorComponent,\n    UiSliderComponent,\n  ],\n  template: `\n    <div data-slot=\"defi-staking-yield-vault\" [class]=\"rootClass\">\n      <!-- Header Section -->\n      <header class=\"border-border/80 bg-card/60 rounded-xl border p-4 shadow-xs backdrop-blur-xs sm:p-6\">\n        <div class=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n          <div class=\"space-y-2\">\n            <div class=\"flex flex-wrap items-center gap-2.5\">\n              <div\n                class=\"bg-primary/10 text-primary border-primary/20 flex size-9 shrink-0 items-center justify-center rounded-lg border shadow-xs\"\n                aria-hidden=\"true\"\n              >\n                <lucide-icon [img]=\"Zap\" class=\"size-5\" />\n              </div>\n              <div>\n                <div class=\"flex flex-wrap items-center gap-2\">\n                  <h1 class=\"text-foreground text-xl font-bold tracking-tight sm:text-2xl\">\n                    ETH Liquid Staking & Yield Vault v3\n                  </h1>\n                  <span ui-badge variant=\"outline\" class=\"border-border/80 font-mono text-xs font-normal\">\n                    v3.2 Protocol\n                  </span>\n                </div>\n              </div>\n            </div>\n\n            <div class=\"flex flex-wrap items-center gap-2.5 text-xs\">\n              <span ui-badge variant=\"outline\" class=\"border-success/30 bg-success/10 text-success gap-1.5 font-normal\">\n                <lucide-icon [img]=\"ShieldCheck\" class=\"size-3.5\" aria-hidden=\"true\" />\n                Audited by Trail of Bits & OpenZeppelin\n              </span>\n              <span ui-badge variant=\"secondary\" class=\"gap-1.5 font-medium tabular-nums\">\n                <span class=\"bg-success size-1.5 animate-pulse rounded-full\" aria-hidden=\"true\"></span>\n                $142,850,000.00 TVL\n              </span>\n              <span class=\"text-muted-foreground hidden items-center gap-1 sm:inline-flex\">\n                <lucide-icon [img]=\"Zap\" class=\"text-warning size-3\" aria-hidden=\"true\" />\n                Auto-Compounding Enabled\n              </span>\n            </div>\n          </div>\n\n          <!-- Wallet Connection Action -->\n          <div class=\"flex flex-wrap items-center gap-2.5\">\n            @if (isWalletConnected()) {\n              <div class=\"border-border bg-muted/60 flex items-center gap-2 rounded-lg border px-3 py-1.5 shadow-xs\">\n                <span class=\"bg-success size-2 rounded-full\" aria-hidden=\"true\"></span>\n                <span class=\"text-foreground font-mono text-xs font-medium\">{{ shortAddress }}</span>\n                <button\n                  ui-button\n                  variant=\"ghost\"\n                  size=\"icon-sm\"\n                  class=\"text-muted-foreground hover:text-foreground size-5\"\n                  aria-label=\"Copy wallet address\"\n                  (click)=\"copyAddress()\"\n                >\n                  @if (copied()) {\n                    <lucide-icon [img]=\"Check\" class=\"text-success size-3\" aria-hidden=\"true\" />\n                  } @else {\n                    <lucide-icon [img]=\"Copy\" class=\"size-3\" aria-hidden=\"true\" />\n                  }\n                </button>\n              </div>\n              <button\n                ui-button\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"shadow-xs active:scale-[0.98]\"\n                (click)=\"isWalletConnected.set(false)\"\n              >\n                Disconnect\n              </button>\n            } @else {\n              <button\n                ui-button\n                size=\"sm\"\n                class=\"gap-2 shadow-xs active:scale-[0.98]\"\n                (click)=\"isWalletConnected.set(true)\"\n              >\n                <lucide-icon [img]=\"Wallet\" class=\"size-4\" aria-hidden=\"true\" />\n                Connect Web3 Wallet\n              </button>\n            }\n          </div>\n        </div>\n      </header>\n\n      <!-- 4 Staking Performance KPI Cards -->\n      <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n        <div ui-card class=\"border-border/80 shadow-xs\">\n          <div ui-card-header class=\"pb-2\">\n            <div class=\"flex items-center justify-between\">\n              <p ui-card-description class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n                Net Staking APY\n              </p>\n              <div\n                class=\"border-success/30 bg-success/10 text-success flex size-7 items-center justify-center rounded-md border\"\n                aria-hidden=\"true\"\n              >\n                <lucide-icon [img]=\"TrendingUp\" class=\"size-4\" />\n              </div>\n            </div>\n            <div class=\"mt-1 flex items-baseline gap-2\">\n              <span class=\"text-success text-2xl font-bold tracking-tight tabular-nums sm:text-3xl\">7.42% APY</span>\n            </div>\n          </div>\n          <div ui-card-content class=\"text-muted-foreground space-y-1 text-xs\">\n            <div class=\"text-success flex items-center gap-1.5 font-medium\">\n              <span class=\"bg-success size-1.5 rounded-full\" aria-hidden=\"true\"></span>\n              Auto-Compounding daily\n            </div>\n            <p class=\"text-muted-foreground tabular-nums\">Base 4.92% + 2.50% MEV Boost</p>\n          </div>\n        </div>\n\n        <div ui-card class=\"border-border/80 shadow-xs\">\n          <div ui-card-header class=\"pb-2\">\n            <div class=\"flex items-center justify-between\">\n              <p ui-card-description class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n                Your Staked Balance\n              </p>\n              <div\n                class=\"border-primary/30 bg-primary/10 text-primary flex size-7 items-center justify-center rounded-md border\"\n                aria-hidden=\"true\"\n              >\n                <lucide-icon [img]=\"Coins\" class=\"size-4\" />\n              </div>\n            </div>\n            <div class=\"mt-1 flex items-baseline gap-2\">\n              <span class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums sm:text-3xl\">24.50 ETH</span>\n            </div>\n          </div>\n          <div ui-card-content class=\"text-muted-foreground space-y-1 text-xs\">\n            <div class=\"text-muted-foreground font-medium tabular-nums\">≈ $84,525.00 USD</div>\n            <div class=\"flex items-center gap-1\">\n              <span ui-badge variant=\"outline\" class=\"border-border/80 px-1.5 py-0 text-xs font-normal\"\n                >Active in Vault v3</span\n              >\n            </div>\n          </div>\n        </div>\n\n        <div ui-card class=\"border-border/80 shadow-xs\">\n          <div ui-card-header class=\"pb-2\">\n            <div class=\"flex items-center justify-between\">\n              <p ui-card-description class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n                Unclaimed Rewards\n              </p>\n              <div\n                class=\"border-warning/30 bg-warning/10 text-warning flex size-7 items-center justify-center rounded-md border\"\n                aria-hidden=\"true\"\n              >\n                <lucide-icon [img]=\"Coins\" class=\"size-4\" />\n              </div>\n            </div>\n            <div class=\"mt-1 flex items-baseline gap-2\">\n              <span class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums sm:text-3xl\"\n                >{{ unclaimedEth() }} stETH</span\n              >\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-2.5 text-xs\">\n            <div class=\"text-muted-foreground font-medium tabular-nums\">≈ \\${{ unclaimedUsd() }} USD</div>\n            <button\n              ui-button\n              variant=\"outline\"\n              size=\"sm\"\n              class=\"h-7 w-full gap-1.5 text-xs font-medium shadow-xs\"\n              [disabled]=\"unclaimedEth() <= 0 || isClaiming()\"\n              (click)=\"handleClaimRewards()\"\n            >\n              @if (isClaiming()) {\n                <lucide-icon [img]=\"RefreshCw\" class=\"size-3 animate-spin\" aria-hidden=\"true\" />\n              } @else if (claimSuccess()) {\n                <lucide-icon [img]=\"Check\" class=\"text-success size-3\" aria-hidden=\"true\" />\n              }\n              {{ isClaiming() ? 'Claiming On-Chain...' : claimSuccess() ? 'Rewards Claimed!' : 'Claim Rewards' }}\n            </button>\n          </div>\n        </div>\n\n        <div ui-card class=\"border-border/80 shadow-xs\">\n          <div ui-card-header class=\"pb-2\">\n            <div class=\"flex items-center justify-between\">\n              <p ui-card-description class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n                Staking Pool Share\n              </p>\n              <div\n                class=\"border-chart-1/30 bg-chart-1/10 text-chart-1 flex size-7 items-center justify-center rounded-md border\"\n                aria-hidden=\"true\"\n              >\n                <lucide-icon [img]=\"Percent\" class=\"size-4\" />\n              </div>\n            </div>\n            <div class=\"mt-1 flex items-baseline gap-2\">\n              <span class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums sm:text-3xl\">0.017%</span>\n            </div>\n          </div>\n          <div ui-card-content class=\"text-muted-foreground space-y-2 text-xs\">\n            <div class=\"flex items-center justify-between\">\n              <span>of total vault</span>\n              <span class=\"text-foreground font-medium tabular-nums\">$142.85M TVL</span>\n            </div>\n            <div class=\"bg-muted/80 h-1.5 w-full overflow-hidden rounded-full\">\n              <div class=\"bg-primary h-full w-[17%] rounded-full\"></div>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <!-- 2-Column Staking Simulator & Yield Directory -->\n      <div class=\"grid grid-cols-1 gap-6 lg:grid-cols-12\">\n        <!-- Left Column: Deposit & Stake Calculator (7 Cols) -->\n        <div class=\"space-y-6 lg:col-span-7\">\n          <div ui-card class=\"border-border/80 shadow-xs\">\n            <div ui-card-header class=\"pb-4\">\n              <div class=\"flex items-center justify-between\">\n                <div class=\"space-y-1\">\n                  <h3 ui-card-title class=\"text-foreground flex items-center gap-2 text-base font-semibold sm:text-lg\">\n                    <lucide-icon [img]=\"Zap\" class=\"text-primary size-5\" aria-hidden=\"true\" />\n                    Deposit & Stake Calculator\n                  </h3>\n                  <p ui-card-description class=\"text-muted-foreground text-xs\">\n                    Simulate staking yields with custom lockup multipliers and real-time auto-compounding.\n                  </p>\n                </div>\n                <span\n                  ui-badge\n                  variant=\"outline\"\n                  class=\"border-success/30 bg-success/10 text-success text-xs font-semibold\"\n                >\n                  {{ effectiveApy() }}% APY\n                </span>\n              </div>\n            </div>\n\n            <div ui-card-content class=\"space-y-5\">\n              <!-- Token Selector Tabs -->\n              <div class=\"space-y-2\">\n                <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                  <label class=\"text-foreground font-medium\">Select Staking Asset</label>\n                  <span class=\"tabular-nums\">Available: {{ currentToken().balance }} {{ currentToken().symbol }}</span>\n                </div>\n                <div class=\"grid grid-cols-3 gap-2\">\n                  @for (token of tokens; track token.symbol) {\n                    <button\n                      type=\"button\"\n                      [class]=\"tokenButtonClass(token.symbol)\"\n                      (click)=\"selectedTokenSymbol.set(token.symbol)\"\n                    >\n                      <div class=\"flex w-full items-center justify-between\">\n                        <div class=\"flex items-center gap-2\">\n                          <span\n                            class=\"size-5 shrink-0 rounded-full shadow-xs\"\n                            [style.background-color]=\"token.iconColor\"\n                            aria-hidden=\"true\"\n                          ></span>\n                          <span class=\"text-foreground text-xs font-semibold\">{{ token.symbol }}</span>\n                        </div>\n                        @if (selectedTokenSymbol() === token.symbol) {\n                          <lucide-icon [img]=\"Check\" class=\"text-primary size-3.5\" aria-hidden=\"true\" />\n                        }\n                      </div>\n                      <span class=\"text-muted-foreground text-xs tabular-nums\">{{ token.balance }} avail.</span>\n                    </button>\n                  }\n                </div>\n              </div>\n\n              <!-- Amount Input & Quick Percentages -->\n              <div class=\"bg-muted/40 border-border/80 space-y-3 rounded-lg border p-4\">\n                <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                  <label for=\"stake-amount-input-angular\" class=\"text-foreground font-medium\">Deposit Amount</label>\n                  <div class=\"flex items-center gap-1.5\">\n                    <span class=\"tabular-nums\">Wallet: {{ currentToken().balance }} {{ currentToken().symbol }}</span>\n                    <button\n                      type=\"button\"\n                      class=\"text-primary hover:text-primary/80 inline-flex min-h-6 items-center px-1 font-semibold uppercase transition-colors focus-visible:outline-none\"\n                      (click)=\"setMaxAmount()\"\n                    >\n                      MAX\n                    </button>\n                  </div>\n                </div>\n                <div class=\"flex items-center justify-between gap-3\">\n                  <ui-input\n                    id=\"stake-amount-input-angular\"\n                    [value]=\"stakeAmountStr()\"\n                    (valueChange)=\"stakeAmountStr.set($event)\"\n                    type=\"number\"\n                    step=\"any\"\n                    min=\"0\"\n                    class=\"h-9 border-none bg-transparent px-0 text-xl font-bold tracking-tight tabular-nums shadow-none focus-visible:ring-0\"\n                    placeholder=\"0.0\"\n                  />\n                  <div\n                    class=\"border-border bg-background flex shrink-0 items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs font-semibold shadow-xs\"\n                  >\n                    <span>{{ currentToken().symbol }}</span>\n                  </div>\n                </div>\n                <div class=\"flex flex-wrap items-center justify-between gap-2 pt-1 text-xs\">\n                  <span class=\"text-muted-foreground tabular-nums\">≈ \\${{ stakedFiatValue() }} USD</span>\n                  <div class=\"flex items-center gap-1\">\n                    @for (pct of [25, 50, 75, 100]; track pct) {\n                      <button\n                        type=\"button\"\n                        class=\"border-border bg-background hover:bg-muted text-muted-foreground hover:text-foreground min-h-6 rounded border px-2 py-0.5 font-mono text-xs transition-[colors,transform] duration-150 focus-visible:ring-1 focus-visible:outline-none active:scale-95\"\n                        (click)=\"setPercentageAmount(pct)\"\n                      >\n                        {{ pct === 100 ? 'MAX' : pct + '%' }}\n                      </button>\n                    }\n                  </div>\n                </div>\n                <div class=\"pt-2\">\n                  <ui-slider\n                    [value]=\"[sliderAmount()]\"\n                    (valueChange)=\"handleSliderChange($event)\"\n                    [min]=\"0\"\n                    [max]=\"currentToken().balance\"\n                    [step]=\"0.1\"\n                    class=\"w-full\"\n                  />\n                </div>\n              </div>\n\n              <!-- Lockup Duration Selector -->\n              <div class=\"space-y-2\">\n                <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                  <span class=\"text-foreground font-medium\">Lockup Duration & Boost</span>\n                  <span class=\"text-muted-foreground\">Longer lockups multiply daily yields</span>\n                </div>\n                <div class=\"grid grid-cols-2 gap-2 sm:grid-cols-4\">\n                  @for (opt of lockups; track opt.id) {\n                    <button type=\"button\" [class]=\"lockupButtonClass(opt.id)\" (click)=\"selectedLockupId.set(opt.id)\">\n                      <div class=\"flex items-center gap-1\">\n                        @if (opt.days === 0) {\n                          <lucide-icon [img]=\"Unlock\" class=\"text-muted-foreground size-3.5\" aria-hidden=\"true\" />\n                        } @else {\n                          <lucide-icon [img]=\"Lock\" class=\"text-primary size-3.5\" aria-hidden=\"true\" />\n                        }\n                        <span class=\"text-foreground text-xs font-semibold\">{{ opt.label }}</span>\n                      </div>\n                      <span ui-badge variant=\"outline\" [class]=\"lockupBadgeClass(opt)\">{{ opt.badge }}</span>\n                    </button>\n                  }\n                </div>\n              </div>\n\n              <!-- Estimated Returns Highlight Box -->\n              <div class=\"border-success/20 bg-success/5 space-y-3 rounded-lg border p-4\">\n                <div class=\"flex items-center justify-between\">\n                  <span class=\"text-foreground flex items-center gap-1.5 text-xs font-semibold\">\n                    <lucide-icon [img]=\"Flame\" class=\"text-success size-4\" aria-hidden=\"true\" />\n                    Estimated Annual Yield\n                  </span>\n                  <span\n                    ui-badge\n                    variant=\"outline\"\n                    class=\"border-success/30 bg-success/10 text-success font-mono text-xs font-semibold\"\n                  >\n                    {{ effectiveApy() }}% APY\n                  </span>\n                </div>\n                <div class=\"flex flex-wrap items-baseline gap-2\">\n                  <span class=\"text-success text-xl font-bold tracking-tight tabular-nums sm:text-2xl\"\n                    >+\\${{ annualYieldUsd() }} / year</span\n                  >\n                  <span class=\"text-muted-foreground font-mono text-xs tabular-nums\"\n                    >({{ annualYieldEth() }} {{ currentToken().symbol }})</span\n                  >\n                </div>\n                <ui-separator class=\"bg-success/20\" />\n                <div class=\"grid grid-cols-2 gap-3 text-xs sm:grid-cols-3\">\n                  <div class=\"space-y-0.5\">\n                    <div class=\"text-muted-foreground\">Daily Returns</div>\n                    <div class=\"text-foreground font-medium tabular-nums\">+\\${{ dailyYieldUsd() }}</div>\n                    <div class=\"text-muted-foreground font-mono text-xs tabular-nums\">\n                      {{ dailyYieldEth() }} {{ currentToken().symbol }}\n                    </div>\n                  </div>\n                  <div class=\"space-y-0.5\">\n                    <div class=\"text-muted-foreground\">Monthly Returns</div>\n                    <div class=\"text-foreground font-medium tabular-nums\">+\\${{ monthlyYieldUsd() }}</div>\n                    <div class=\"text-muted-foreground font-mono text-xs tabular-nums\">\n                      {{ monthlyYieldEth() }} {{ currentToken().symbol }}\n                    </div>\n                  </div>\n                  <div class=\"col-span-2 space-y-0.5 sm:col-span-1\">\n                    <div class=\"text-muted-foreground\">Network Gas & Fee</div>\n                    <div class=\"text-foreground flex items-center gap-1 font-medium tabular-nums\">\n                      <lucide-icon [img]=\"Fuel\" class=\"text-muted-foreground size-3\" aria-hidden=\"true\" />\n                      ~$2.85 (0% fee)\n                    </div>\n                    <div class=\"text-success text-xs\">No exit penalty</div>\n                  </div>\n                </div>\n              </div>\n\n              <!-- Primary Stake CTA Button -->\n              <button\n                ui-button\n                size=\"lg\"\n                class=\"w-full gap-2 font-semibold shadow-xs active:scale-[0.98]\"\n                [disabled]=\"parsedAmount() <= 0 || isStaking()\"\n                (click)=\"handleExecuteStake()\"\n              >\n                @if (isStaking()) {\n                  <lucide-icon [img]=\"RefreshCw\" class=\"size-4 animate-spin\" aria-hidden=\"true\" />\n                } @else if (stakeSuccess()) {\n                  <lucide-icon [img]=\"Check\" class=\"text-success size-4\" aria-hidden=\"true\" />\n                } @else {\n                  <lucide-icon [img]=\"Zap\" class=\"size-4\" aria-hidden=\"true\" />\n                }\n                {{\n                  isStaking()\n                    ? 'Submitting Staking Transaction...'\n                    : stakeSuccess()\n                      ? 'Successfully Staked ' + parsedAmount() + ' ' + currentToken().symbol + '!'\n                      : 'Stake ' + (parsedAmount() > 0 ? parsedAmount() + ' ' + currentToken().symbol : 'ETH') + ' Now'\n                }}\n              </button>\n\n              <div class=\"text-muted-foreground flex items-center justify-center gap-2 text-center text-xs\">\n                <lucide-icon [img]=\"ShieldCheck\" class=\"text-success size-3.5\" aria-hidden=\"true\" />\n                <span>Smart contracts verified on Etherscan · 100% non-custodial</span>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <!-- Right Column: Yield Vaults Directory (5 Cols) -->\n        <div class=\"space-y-6 lg:col-span-5\">\n          <div ui-card class=\"border-border/80 shadow-xs\">\n            <div ui-card-header class=\"pb-3\">\n              <div class=\"flex items-center justify-between\">\n                <div>\n                  <h3 ui-card-title class=\"text-foreground text-base font-semibold\">Yield Vaults Directory</h3>\n                  <p ui-card-description class=\"text-muted-foreground text-xs\">\n                    Active liquidity pools and automated yield strategies.\n                  </p>\n                </div>\n                <span ui-badge variant=\"secondary\" class=\"text-xs font-normal tabular-nums\">3 Vaults Active</span>\n              </div>\n            </div>\n            <div ui-card-content class=\"space-y-3.5\">\n              @for (vault of vaults; track vault.id) {\n                <div [class]=\"vaultCardClass(vault)\">\n                  <div class=\"flex items-start justify-between gap-2\">\n                    <div class=\"space-y-1\">\n                      <div class=\"flex items-center gap-2\">\n                        <span class=\"text-foreground text-sm font-semibold\">{{ vault.name }}</span>\n                        @if (vault.isCurrentVault) {\n                          <span\n                            ui-badge\n                            variant=\"outline\"\n                            class=\"border-primary/40 bg-primary/10 text-primary px-1.5 py-0 text-xs font-medium\"\n                            >Current</span\n                          >\n                        }\n                      </div>\n                      <p class=\"text-muted-foreground text-xs\">{{ vault.protocol }}</p>\n                    </div>\n                    <div class=\"text-right\">\n                      <div class=\"text-success text-base font-bold tabular-nums sm:text-lg\">{{ vault.apy }} APY</div>\n                      <div class=\"text-muted-foreground font-mono text-xs tabular-nums\">{{ vault.tvl }}</div>\n                    </div>\n                  </div>\n                  <div\n                    class=\"border-border/60 bg-muted/30 flex flex-wrap items-center justify-between gap-2 rounded-md border p-2 text-xs\"\n                  >\n                    <div class=\"flex items-center gap-1.5\">\n                      <span ui-badge variant=\"outline\" [class]=\"riskBadgeClass(vault)\">{{ vault.risk }}</span>\n                      <span class=\"text-muted-foreground max-w-[140px] truncate sm:max-w-none\">{{\n                        vault.strategy\n                      }}</span>\n                    </div>\n                    <div class=\"text-muted-foreground font-medium tabular-nums\">{{ vault.metricValue }}</div>\n                  </div>\n                  <div class=\"flex items-center justify-between pt-1\">\n                    <span class=\"text-muted-foreground font-mono text-xs\">{{ vault.pairSymbol }}</span>\n                    <button\n                      ui-button\n                      [variant]=\"vault.isCurrentVault ? 'default' : 'outline'\"\n                      size=\"sm\"\n                      class=\"h-7 px-3 text-xs shadow-xs\"\n                    >\n                      <span>{{ vault.isCurrentVault ? 'Manage Vault' : 'Deposit Pool' }}</span>\n                      <lucide-icon [img]=\"ArrowUpRight\" class=\"ml-1 size-3\" aria-hidden=\"true\" />\n                    </button>\n                  </div>\n                </div>\n              }\n            </div>\n            <div\n              ui-card-footer\n              class=\"border-border/60 bg-muted/20 flex flex-col gap-2 rounded-b-xl border-t p-3.5 text-xs\"\n            >\n              <div class=\"text-muted-foreground flex items-center gap-2\">\n                <lucide-icon [img]=\"ShieldAlert\" class=\"text-warning size-4 shrink-0\" aria-hidden=\"true\" />\n                <span>Yields adjust dynamically with Ethereum validator queue and DEX trading fee volumes.</span>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  `,\n})\nexport class UiDefiStakingYieldVaultComponent {\n  protected readonly ArrowUpRight = ArrowUpRight\n  protected readonly Check = Check\n  protected readonly Coins = Coins\n  protected readonly Copy = Copy\n  protected readonly Flame = Flame\n  protected readonly Fuel = Fuel\n  protected readonly Lock = Lock\n  protected readonly Percent = Percent\n  protected readonly RefreshCw = RefreshCw\n  protected readonly ShieldAlert = ShieldAlert\n  protected readonly ShieldCheck = ShieldCheck\n  protected readonly TrendingUp = TrendingUp\n  protected readonly Unlock = Unlock\n  protected readonly Wallet = Wallet\n  protected readonly Zap = Zap\n\n  protected readonly tokens = tokenOptions\n  protected readonly lockups = lockupOptions\n  protected readonly vaults = yieldVaults\n  protected readonly shortAddress = '0x71C...3a9F'\n\n  @Input() set initialToken(v: string) {\n    if (v) this.selectedTokenSymbol.set(v)\n  }\n  @Input() set initialLockup(v: string) {\n    if (v) this.selectedLockupId.set(v)\n  }\n  @Input('class') className?: string\n\n  readonly isWalletConnected = signal(true)\n  readonly copied = signal(false)\n  readonly unclaimedEth = signal(0.485)\n  readonly isClaiming = signal(false)\n  readonly claimSuccess = signal(false)\n\n  readonly selectedTokenSymbol = signal('ETH')\n  readonly selectedLockupId = signal('flex')\n  readonly stakeAmountStr = signal('10.0')\n  readonly isStaking = signal(false)\n  readonly stakeSuccess = signal(false)\n\n  readonly currentToken = computed(\n    () => tokenOptions.find((t) => t.symbol === this.selectedTokenSymbol()) ?? tokenOptions[0]!,\n  )\n  readonly currentLockup = computed(\n    () => lockupOptions.find((l) => l.id === this.selectedLockupId()) ?? lockupOptions[0]!,\n  )\n  readonly parsedAmount = computed(() => {\n    const val = parseFloat(this.stakeAmountStr())\n    return isNaN(val) || val < 0 ? 0 : val\n  })\n  readonly sliderAmount = computed(() => Math.min(this.parsedAmount(), this.currentToken().balance))\n\n  readonly baseVaultApy = 7.42\n  readonly effectiveApy = computed(() =>\n    (this.baseVaultApy + this.currentLockup().boost + this.currentToken().apyBoost).toFixed(2),\n  )\n  readonly stakedFiatValue = computed(() => fmtUsd(this.parsedAmount() * this.currentToken().price))\n  readonly unclaimedUsd = computed(() => fmtUsd(this.unclaimedEth() * 3450))\n\n  private yieldUsd(divisor: number): string {\n    const rate = parseFloat(this.effectiveApy()) / 100\n    return fmtUsd((this.parsedAmount() * rate * this.currentToken().price) / divisor)\n  }\n\n  private yieldEth(divisor: number, digits: number): string {\n    const rate = parseFloat(this.effectiveApy()) / 100\n    return ((this.parsedAmount() * rate) / divisor).toFixed(digits)\n  }\n\n  readonly annualYieldUsd = computed(() => this.yieldUsd(1))\n  readonly annualYieldEth = computed(() => this.yieldEth(1, 3))\n  readonly monthlyYieldUsd = computed(() => this.yieldUsd(12))\n  readonly monthlyYieldEth = computed(() => this.yieldEth(12, 4))\n  readonly dailyYieldUsd = computed(() => this.yieldUsd(365))\n  readonly dailyYieldEth = computed(() => this.yieldEth(365, 5))\n\n  get rootClass(): string {\n    return cn('mx-auto w-full max-w-6xl space-y-6', this.className)\n  }\n\n  tokenButtonClass(symbol: string): string {\n    return cn(\n      'border-border/80 focus-visible:ring-ring flex flex-col items-start gap-1 rounded-lg border p-3 text-left transition-[colors,transform] duration-150 focus-visible:ring-2 focus-visible:outline-none active:scale-[0.98]',\n      this.selectedTokenSymbol() === symbol\n        ? 'border-primary bg-primary/5 ring-primary/20 shadow-xs ring-1'\n        : 'bg-card hover:bg-muted/50 text-muted-foreground',\n    )\n  }\n\n  lockupButtonClass(id: string): string {\n    return cn(\n      'border-border/80 focus-visible:ring-ring flex flex-col items-center justify-center gap-1 rounded-lg border p-2.5 text-center transition-[colors,transform] duration-150 focus-visible:ring-2 focus-visible:outline-none active:scale-[0.98]',\n      this.selectedLockupId() === id\n        ? 'border-primary bg-primary/5 ring-primary/20 shadow-xs ring-1'\n        : 'bg-card hover:bg-muted/50 text-muted-foreground',\n    )\n  }\n\n  lockupBadgeClass(opt: VaultLockupOption): string {\n    return cn(\n      'border-border/60 font-mono text-xs font-normal tabular-nums',\n      opt.boost > 0 ? 'border-success/30 text-success' : 'text-muted-foreground',\n    )\n  }\n\n  vaultCardClass(vault: VaultItem): string {\n    return cn(\n      'border-border/80 relative space-y-3 rounded-lg border p-3.5 transition-colors',\n      vault.isCurrentVault ? 'bg-primary/5 border-primary/40 ring-primary/20 ring-1' : 'bg-card hover:bg-muted/30',\n    )\n  }\n\n  riskBadgeClass(vault: VaultItem): string {\n    return cn(\n      'px-1.5 py-0 text-xs font-normal',\n      vault.riskVariant === 'emerald'\n        ? 'border-success/30 bg-success/10 text-success'\n        : 'border-warning/30 bg-warning/10 text-warning',\n    )\n  }\n\n  copyAddress(): void {\n    try {\n      void navigator.clipboard?.writeText(walletAddress)\n    } catch {\n      // Clipboard unavailable in some contexts; the flag still flips for feedback.\n    }\n    this.copied.set(true)\n    setTimeout(() => this.copied.set(false), 2000)\n  }\n\n  handleClaimRewards(): void {\n    if (this.unclaimedEth() <= 0 || this.isClaiming()) return\n    this.isClaiming.set(true)\n    setTimeout(() => {\n      this.isClaiming.set(false)\n      this.claimSuccess.set(true)\n      this.unclaimedEth.set(0)\n      setTimeout(() => this.claimSuccess.set(false), 3500)\n    }, 1200)\n  }\n\n  handleSliderChange(vals: number[]): void {\n    if (vals?.[0] !== undefined) this.stakeAmountStr.set(vals[0].toFixed(2))\n  }\n\n  setPercentageAmount(pct: number): void {\n    this.stakeAmountStr.set((this.currentToken().balance * (pct / 100)).toFixed(2))\n  }\n\n  setMaxAmount(): void {\n    this.stakeAmountStr.set(this.currentToken().balance.toFixed(2))\n  }\n\n  handleExecuteStake(): void {\n    if (this.parsedAmount() <= 0 || this.isStaking()) return\n    this.isStaking.set(true)\n    setTimeout(() => {\n      this.isStaking.set(false)\n      this.stakeSuccess.set(true)\n      setTimeout(() => this.stakeSuccess.set(false), 3500)\n    }, 1400)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/defi-staking-yield-vault/defi-staking-yield-vault.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/defi-staking-yield-vault/index.ts",
      "content": "export { UiDefiStakingYieldVaultComponent } from './defi-staking-yield-vault.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/defi-staking-yield-vault/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/input.json",
    "https://uipkge.dev/r/angular/separator.json",
    "https://uipkge.dev/r/angular/slider.json"
  ],
  "description": "Nodeka and Uniswap-inspired decentralized finance staking yield vault, liquidity pool APY calculator, and reward claimer with live TVL metrics, multi-tier lockup multipliers, and real-time yield simulator.",
  "categories": [
    "finance",
    "app",
    "dashboard"
  ]
}