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

@steerprotocol/curator-tools

v1.7.0

Published

Steer Protocol Curator Override Tools

Readme

Steer Curator Override Registry

This project implements a centralized "Top-Level Authority" for the EAS (Ethereum Attestation Service) Key-Value store. It allows a protocol administrator to manage a registry of authorized curators who can attest to vault-specific overrides (e.g., updating strategy IPFS hashes).

Components

Smart Contracts

  • SteerAuthorityResolver.sol: An EAS Schema Resolver that enforces curator permissions. It validates that the attester is authorized for the specified vault; the attestation payload includes a targetChainId for cross-chain overrides stored canonically on Arbitrum One.
  • Access Control: Uses OpenZeppelin's Ownable2Step for secure management of the top-level authority role.

Management Tooling

  • ManageCurators.s.sol: A Foundry script for programmatically authorizing or revoking curators via CLI.

Client-Side Integration

  • StrategyStore.ts: A TypeScript class providing helpers to check admin status, curator authorization, and encode management transactions. Includes built-in Zod validation for runtime safety.

Getting Started

Prerequisites

Installation

  1. Install Foundry dependencies:
    forge install
  2. Install Node dependencies:
    npm install

Testing

  • Run Smart Contract tests:
    forge test
  • Run Client-Side tests:
    npm test

Features

  • Curator gating (per vault): Only admins can authorize/revoke curators per vault via setCurator(vault, curator, status).
  • Cross-chain overrides (canonical on Arbitrum One): The payload includes a targetChainId (encoded in the chainId field) so overrides for many chains can be stored on Arbitrum One.
  • Two-step admin transfers: Uses OpenZeppelin Ownable2Step (transferOwnership + acceptOwnership) to reduce lockout risk.
  • Operational scripting: Foundry scripts for deployment, curator management, and admin migration.
  • TypeScript client (StrategyStore):
    • Reads admin + curator status (isAdmin, isCurator).
    • Encodes admin transactions (registerCuratorTx) for dashboards.
    • Optional strict vault validation via VaultRegistry.getVaultDetails(...).
    • Address resolution via @steerprotocol/sdk with a temporary Arbitrum resolver override.

EAS Schema (Option B: Cross-Chain Overrides)

Canonical overrides are stored on Arbitrum One, and the payload’s chainId field is treated as a targetChainId.

  • Schema string: address vault,uint256 chainId,uint256 strategyTokenId,string manifestCid
  • Semantics: chainId is targetChainId (it may differ from block.chainid)
  • SchemaRegistry (Arbitrum One): 0xA310da9c5B885E7fb3fbA9D66E9Ba6Df512b78eB
  • Resolver (Arbitrum One): 0x6628d1Bf82F34de132d0e1c60DEB574C1352d5A7
  • Schema revocable: true
  • Schema UID: 0xf1a6a394d1f3dd832a15e5b750963d929812e2b74d2dcea68ddf9f75691f16bf
  • Deprecated schema (no resolver): 0x62b656756a16bd3d2ef501cd9493c603fd90b050d6e9cfffc8e450639ce30a27 (registered with resolver address(0), so it enforces no on-chain curator checks)

User Flows

Admin

  1. Deploy SteerAuthorityResolver.
  2. Authorize/revoke curators per vault.
  3. Migrate admin control to a new owner (EOA or multisig) using the 2-step ownership flow.

Curator

  1. Create an EAS attestation for a vault override.
  2. Resolver validates curator authorization for the target vault.
  3. If valid, the attestation is recorded by EAS. The payload includes a targetChainId so indexers/integrators can interpret which chain the override applies to.

Integrator (frontend / indexer / backend)

  1. Read curator authorization per vault.
  2. (Optional) Validate vault addresses via VaultRegistry before trusting overrides.
  3. Build admin UI flows by generating to/data transactions via StrategyStore.

Usage

Deploying the Resolver (Foundry)

Deploys on Arbitrum One using the official Arbitrum One EAS address hardcoded in script/DeploySteerAuthorityResolver.s.sol.

export PRIVATE_KEY=<DEPLOYER_PRIVATE_KEY>
export RPC_URL=<ARBITRUM_ONE_RPC_URL>

forge script script/DeploySteerAuthorityResolver.s.sol:DeploySteerAuthorityResolver --rpc-url "$RPC_URL" --broadcast

Broadcast results (including deployed address) are written under broadcast/.

Registering the Cross-Chain Schema (Foundry)

Registers a new schema on Arbitrum One’s SchemaRegistry with SteerAuthorityResolver as the resolver.

export PRIVATE_KEY=<REGISTERER_PRIVATE_KEY>
export RPC_URL=<ARBITRUM_ONE_RPC_URL>
export RESOLVER_ADDRESS=<DEPLOYED_RESOLVER>

forge script script/RegisterSteerCrosschainSchema.s.sol:RegisterSteerCrosschainSchema --rpc-url "$RPC_URL" --broadcast

Encoding (Solidity)

bytes memory data = abi.encode(vault, targetChainId, strategyTokenId, manifestCid);

Encoding (TypeScript)

const data = StrategyStore.encodeOverrideAttestationData(vault, targetChainId, 1n, manifestCid);

Managing Curators via CLI

Authorize/revoke a curator for a specific vault.

export RESOLVER_ADDRESS=<DEPLOYED_RESOLVER>
export VAULT=<VAULT_ADDRESS>
export CURATOR=<CURATOR_ADDRESS>
export STATUS=true # true to authorize, false to revoke
export PRIVATE_KEY=<ADMIN_PRIVATE_KEY>
export RPC_URL=<ARBITRUM_ONE_RPC_URL>

forge script script/ManageCurators.s.sol:ManageCurators --rpc-url "$RPC_URL" --broadcast

Migrating Admin Control (Ownership)

Admin migration is a 2-step flow because the resolver uses Ownable2Step.

Step 1: Initiate transfer (current admin)

export RESOLVER_ADDRESS=<DEPLOYED_RESOLVER>
export NEW_OWNER=<NEW_ADMIN_ADDRESS>
export PRIVATE_KEY=<CURRENT_ADMIN_PRIVATE_KEY>
export RPC_URL=<ARBITRUM_ONE_RPC_URL>

forge script script/MigrateAdminControl.s.sol:MigrateAdminControl --rpc-url "$RPC_URL" --broadcast

Step 2: Accept ownership (new admin)

export RESOLVER_ADDRESS=<DEPLOYED_RESOLVER>
export ONLY_ACCEPT=true
export NEW_OWNER_PRIVATE_KEY=<NEW_ADMIN_PRIVATE_KEY>
export RPC_URL=<ARBITRUM_ONE_RPC_URL>

forge script script/MigrateAdminControl.s.sol:MigrateAdminControl --rpc-url "$RPC_URL" --broadcast

Verifying Admin Migration

Use cast to confirm owner() and pendingOwner() on-chain.

export RESOLVER_ADDRESS=<DEPLOYED_RESOLVER>
export RPC_URL=<ARBITRUM_ONE_RPC_URL>

cast call "$RESOLVER_ADDRESS" "owner()(address)" --rpc-url "$RPC_URL"
cast call "$RESOLVER_ADDRESS" "pendingOwner()(address)" --rpc-url "$RPC_URL"

Using the TypeScript Client

The @steerprotocol/curator-tools client (provided by the StrategyStore class) provides helpers to interact with the authority layer.

import { StrategyStore } from '@steerprotocol/curator-tools';
import { ethers } from 'ethers';

const provider = new ethers.JsonRpcProvider(RPC_URL);

// Automatic resolution for supported networks (e.g., Arbitrum: 42161)
const store = new StrategyStore({ chainId: 42161 }, provider);

// OR explicit addresses
const store2 = new StrategyStore(
  {
    resolverAddress: '0x...',
    registryAddress: '0x...', // Optional: Enables strict vault validation
    chainId: 42161, // Required for curator checks/updates
  },
  provider
);

// Check if a curator is authorized (includes strict vault validation if registry is set)
const authorized = await store2.isCurator(vaultAddress, curatorAddress);

// Generate tx data for an admin dashboard
const tx = await store2.registerCuratorTx(vaultAddress, curatorAddress, true);

Contract Verification on Arbiscan (optional)

If you want to verify the deployed resolver source, you can use forge verify-contract.

export ARBISCAN_API_KEY=<API_KEY>

forge verify-contract \
  --chain-id 42161 \
  --watch \
  --etherscan-api-key "$ARBISCAN_API_KEY" \
  <DEPLOYED_RESOLVER> \
  src/SteerAuthorityResolver.sol:SteerAuthorityResolver \
  --constructor-args $(cast abi-encode "constructor(address)" 0xbD75f629A22Dc1ceD33dDA0b68c546A1c035c458)

CI/CD Pipeline

The project uses GitHub Actions for continuous integration and delivery.

Automated Testing

On every pull request and push to master, the following checks are performed:

  • Smart Contracts: Solidity formatting check (forge fmt) and unit tests (forge test).
  • Client Package: TypeScript type-checking (tsc) and unit tests (npm test).

Automated Releases

Automated versioning and NPM publishing are handled via Semantic Release.

  • Releases are triggered on every push to the master branch after tests pass.
  • Version numbers and changelogs are automatically generated based on Conventional Commits.
  • Required Secrets: To enable publishing, ensure the repository has an NPM_TOKEN secret configured.

Security

  • All administrative actions are restricted to the owner.
  • Resolver validation enforces curator authorization per vault on both attestation and revocation (removing a curator prevents them from attesting and revoking prior attestations).
  • The payload includes a targetChainId for cross-chain overrides stored on Arbitrum One.
  • Input validation is enforced on both smart contract and client-side levels. \n- Multi-chain support: Enhanced StrategyStore to handle multi-chain configurations and deterministic vault identifiers.