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

@lazysuperheroes/hedera-verify

v0.2.0

Published

Verify Hedera smart contracts on Sourcify (sourcify.dev V2 API) — engine, CLI, deploy-time hook, and EIP-1167 clone resolution for Hardhat-built Hedera contracts.

Readme

@lazysuperheroes/hedera-verify

Verify Hedera smart contracts on Sourcify (sourcify.dev) — the engine, CLI, and deploy-time hook, in one small package you can drop into any Hardhat-based Hedera repo.

HashScan retired its self-hosted Sourcify and now points at the public Sourcify, which natively supports Hedera mainnet (chain 295) and testnet (chain 296). Sourcify also retired its V1 /verify API — this package speaks the current V2 job-based API. Everything it needs is already in your Hardhat build-info, so there's no source flattening or metadata hand-assembly.

Install

yarn add -D @lazysuperheroes/hedera-verify
# or: npm i -D @lazysuperheroes/hedera-verify

Requires Node ≥ 18. Reads .env from the current directory. No private key needed — verification is read-only (mirror node + Sourcify).

Quick start (CLI)

# Verify one contract, by Hedera ID or EVM address:
npx hedera-verify LazySecureTrade 0.0.7540226
npx hedera-verify BidderContractFactory 0xabc...123

# Verify everything in your verify.config.js registry that has a deployed id in .env:
npx hedera-verify harness

# Plus ad-hoc targets and filters:
npx hedera-verify harness LazyRebatePool=0.0.123456 --only LazySecureTrade,LazyGasStation

# Inspect:
npx hedera-verify list             # config registry + which .env ids are set
npx hedera-verify list-artifacts   # every compiled contract (to build your config)

ENVIRONMENT (from .env, e.g. test/main) selects the chain; override with --env.

Config

Copy verify.config.example.js to verify.config.js in your repo root and map each contract to the .env var(s) holding its deployed Hedera ID:

module.exports = {
  registry: [
    { contractName: 'MyContract', envVars: ['MY_CONTRACT_ID'] },
    { contractName: 'Legacy', envVars: ['LEGACY_ID'], sourceName: 'contracts/legacy/Legacy.sol' },
  ],
};

Run npx hedera-verify list-artifacts to see every compiled contract and its sourceName. A "hederaVerify" key in package.json works as an alternative to the file.

Deploy-time hook (runtime verification)

Call the engine straight from your deploy script, right after the contract is created. The wait + retry covers the few seconds the mirror node / Sourcify's RPC need to index a fresh contract:

const { verifyContract } = require('@lazysuperheroes/hedera-verify');

const [contractId] = await contractDeployFunction(client, bytecode, gas, params);

if (process.env.VERIFY_ON_DEPLOY === 'true') {
  await verifyContract({
    contractName: 'MyContract',
    env: process.env.ENVIRONMENT,
    contractId,            // Hedera ID or { address: '0x..' }
    initialDelayMs: 10000, // let the network index it
    attempts: 4,           // re-submit on transient "not yet indexed" failures
  });
}

Hardhat plugin fallback

For a manual npx hardhat verify, add a sourcify block and Hedera networks to hardhat.config.js:

networks: {
  testnet: { url: 'https://testnet.hashio.io/api', chainId: 296 },
  mainnet: { url: 'https://mainnet.hashio.io/api', chainId: 295 },
},
sourcify: { enabled: true, apiUrl: 'https://sourcify.dev/server', browserUrl: 'https://repo.sourcify.dev' },
// requires @nomicfoundation/hardhat-verify >= 2.0; then add: etherscan: { enabled: false }

This package's direct V2 path is the recommended route — the plugin is just a convenience fallback. Older [email protected] (bundled by hardhat-toolbox v3) only registers an Etherscan-oriented task and has no clean Hedera Sourcify path; bump to ^2.0.0.

Foundry repos

This package reads Hardhat build-info. For a Foundry project, verify directly with forge:

forge verify-contract --chain-id 296 \
  --verifier sourcify --verifier-url https://sourcify.dev/server \
  <0xADDRESS> src/MyContract.sol:MyContract

API

const v = require('@lazysuperheroes/hedera-verify');

verifyContract(opts) → Promise<Result>

Verify one contract. Key options:

  • contractName (string, required unless build is given)
  • env (string, required)test|main|preview|local
  • contractId (string) — Hedera 0.0.x, resolved to its EVM address via the mirror node
  • address (string)0x… EVM address (takes precedence over contractId)
  • sourceName (string) — disambiguate when the source path ≠ contracts/<Name>.sol
  • build (object) — pre-resolved { stdJsonInput, compilerVersion, contractIdentifier } to verify a non-Hardhat build
  • creationTransactionHash (string) — optional, improves match grade
  • skipIfVerified (bool, default true), initialDelayMs, attempts, retryDelayMs, pollIntervalMs (4000), maxPollAttempts (45), apiUrl, browserUrl, artifactsRoot, quiet

Result: { contractName, contractIdentifier, address, chainId, env, status, match, creationMatch, runtimeMatch, repoUrl, hashscanUrl, message, raw }.

statusverified | already_verified | pending | failed | error. matchexact_match | match | null.

verifyContracts(targets, shared) → Promise<Result[]>

Verify many (sequential). Each target is a verifyContract opts object; shared is merged into all.

Helpers

resolveBuildInfo({contractName, sourceName?, artifactsRoot?}), listArtifacts(artifactsRoot?), resolveEvmAddress({env, address?, contractId?}), getContractEvmAddress(env, id), checkVerified({apiUrl?, chainId, address}), chainIdForEnv(env), hashscanNetwork(env), loadConfig(cwd?), buildRegistryTargets(registry, {only?}), parseAdHocTarget(token).

EIP-1167 minimal-proxy / clone resolution

Clones deployed via Clones.cloneDeterministic (e.g. per-user "stash" contracts) are ~45-byte EIP-1167 minimal proxies. They cannot be source-verified on Sourcify (no .sol compiles to the bare proxy) — verify the implementation once, then resolve clones to it:

  • resolveProxyStatus({env, address|contractId, expectedImplementation?, apiUrl?}){ isProxy, proxyType, implementation, isCanonical, implementationVerified, implementationMatch, bytecode, hashscanUrl }. The function a DApp uses to present a clone with its implementation's name/ABI, and an audit uses to validate clones against an expected implementation. Browser-safe.
  • parseMinimalProxyImplementation(bytecode) → impl address (0x) or null.
  • isMinimalProxyFor(bytecode, impl) → boolean (canonical match).
  • minimalProxyRuntime(impl) → the canonical EIP-1167 runtime for an impl.
  • getOnchainRuntimeBytecode(env, addressOrId) → runtime bytecode from the mirror node.

Note: most explorers (Etherscan/Blockscout) surface a clone's implementation via EIP-1167 detection in the UI. HashScan currently derives "verified" purely from Sourcify, so a clone shows unverified there — resolve it DApp-side with resolveProxyStatus.

Match grades

  • exact_match — full match including metadata. The strongest grade.
  • match (partial) — runtime bytecode matches and source is fully shown, but the embedded metadata hash differs (e.g. the contract compiled in a separate build-info unit). Still verified; the difference is cosmetic.

Gotchas

  • Async jobs. Big viaIR contracts can take longer than the default poll window. A local poll timeout returns pending — the job keeps running on Sourcify, and a re-run's already-verified precheck will confirm it. Raise --poll-attempts if you want a single pass to wait longer.
  • Right after deploy, the mirror node needs a few seconds to index a new contract. Use initialDelayMs + attempts in the deploy hook.
  • Legacy / old deployments compiled with different settings than current source will report bytecode_length_mismatch — that's a real "won't match", not a bug.

Migrating an existing repo

See AGENT-MIGRATION.md — a ready-to-paste prompt for an AI coding agent (e.g. Claude Code) that installs this package, builds the verify.config.js from your repo's deploy scripts/.env, wires the deploy-time hook, and runs the harness.

License

ISC