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

@polygonlabs/spol-contracts-sdk

v0.0.1

Published

Typed [viem](https://viem.sh) contract clients for the sPOL protocol, covering L1 (Ethereum mainnet / Sepolia) and L2 (Polygon / Amoy).

Downloads

52

Readme

spol-contracts-sdk

Typed viem contract clients for the sPOL protocol, covering L1 (Ethereum mainnet / Sepolia) and L2 (Polygon / Amoy).

The sPOL protocol spans ~10 smart contracts across two chains. Without a central SDK, every service would copy the same ABIs, hardcode the same addresses, and redefine the same event signatures — diverging silently as the protocol evolves. This package provides a single source of truth: ABIs defined once, addresses defaulting to production values (overridable per-service via env vars), and event signatures co-located with their ABI entries.

Development

bun run build      # compile to dist/
bun run typecheck  # type-check without emitting

Entry points

| Entry point | Contents | | ------------------------------ | --------------------------------------------------------- | | spol-contracts-sdk | createL1Contracts, createL2Contracts — primary API | | spol-contracts-sdk/events | Per-contract event objects { signature, eventABI } | | spol-contracts-sdk/factories | Per-contract factory functions (custom address use cases) | | spol-contracts-sdk/abis | Raw ABI exports (non-viem use cases) |

Usage

Primary API — createL1Contracts / createL2Contracts

Pass any viem PublicClient or WalletClient. The chain ID is read from the client to select the right contract addresses automatically. All contracts and event objects for that chain are returned together in one bundle.

import { createL1Contracts, createL2Contracts } from 'spol-contracts-sdk';
import { createPublicClient, http } from 'viem';
import { mainnet, polygon } from 'viem/chains';

const l1Contracts = createL1Contracts(
  createPublicClient({ chain: mainnet, transport: http(l1RpcUrl) })
);
const l2Contracts = createL2Contracts(
  createPublicClient({ chain: polygon, transport: http(l2RpcUrl) })
);

Why this over direct factory/ABI imports:

  • All contracts for a chain in one object — no scattered imports or address lookups.
  • Chain ID drives address selection — no network-conditional branching, no address env vars to manage.
  • Type safety propagates from your client: PublicClient → read-only methods; WalletClient → write methods too.
  • Throws at construction on an unsupported chain — fails fast rather than silently at call time.

Calling contract functions

const totalSupply = await l1Contracts.spol.read.totalSupply();
const nonce = await l1Contracts.spolController.read.globalWithdrawNonce();
const hash = await l1Contracts.spolMessenger.write.updateL2ExchangeRate(); // WalletClient only

Getting a contract address

Addresses live on the contract object — access them directly rather than importing a separate address module.

const controllerAddress = l1Contracts.spolController.address;
const childAddress = l2Contracts.sPOLChild.address;

The correct address for the connected chain is always present.

Events (from contracts)

Events are bundled alongside contract instances — prefer this when you already have a client.

// Topic hash for filtering raw logs
l2Contracts.sPOLChildEvents.ExchangeRateUpdated.signature;
l1Contracts.withdrawManagerEvents.ExitStarted.signature;

// Typed ABI entry for event consumer configs
l2Contracts.sPOLChildEvents.sPOLMinted.eventABI;
l1Contracts.sPOLMessengerEvents.MigrationProcessed.eventABI;

Sub-paths

Use only when the primary API doesn't fit your context.

spol-contracts-sdk/events

Use when you need event objects but have no viem client — typically when building event consumer configs at service startup before a client exists:

import {
  sPOLChildEvents,
  sPOLMessengerEvents,
  withdrawManagerEvents
} from 'spol-contracts-sdk/events';

const config: IEventConsumerConfig = {
  contractAddress: '0x...',
  events: [
    sPOLChildEvents.sPOLMinted.eventABI,
    sPOLChildEvents.sPOLBurned.eventABI
  ] as unknown as IEventConsumerConfig['events']
};

Each event entry shape: { signature: '0x...', eventABI: { type, name, inputs, anonymous } } as const.

The as unknown as cast is required because viem's as const produces readonly types narrower than the mutable array type some consumer frameworks expect.

spol-contracts-sdk/abis

Only when passing a raw ABI to non-viem code (e.g. ethers.Contract):

import { sPOLControllerAbi } from 'spol-contracts-sdk/abis';
const contract = new ethers.Contract(address, sPOLControllerAbi, provider);

spol-contracts-sdk/factories

Only when you need a viem contract at a custom address not in the SDK config:

import { getSPolChildContract } from 'spol-contracts-sdk/factories';
const contract = getSPolChildContract({ address: customAddress, client });

Supported chains

| Layer | Chain | Chain ID | | ----- | ---------------- | -------- | | L1 | Ethereum mainnet | 1 | | L1 | Sepolia | 11155111 | | L2 | Polygon | 137 | | L2 | Amoy | 80002 |

Passing a client on an unsupported chain throws immediately with a clear error listing the supported chain IDs.


Contract addresses

Default addresses are hardcoded in src/config.ts and can be overridden via environment variables — useful for local development or fork testing. Invalid values are silently ignored and the hardcoded default is used instead.

| Chain | Contract | Env var | | ---------------- | ---------------- | ---------------------------- | | Ethereum mainnet | sPOL | MAINNET_SPOL | | Ethereum mainnet | sPOLController | MAINNET_SPOL_CONTROLLER | | Ethereum mainnet | sPOLMessenger | MAINNET_SPOL_MESSENGER | | Ethereum mainnet | polBridger | MAINNET_POL_BRIDGER | | Ethereum mainnet | rootChainManager | MAINNET_ROOT_CHAIN_MANAGER | | Ethereum mainnet | stakeManager | MAINNET_STAKE_MANAGER | | Ethereum mainnet | validatorShare | MAINNET_VALIDATOR_SHARE | | Ethereum mainnet | withdrawManager | MAINNET_WITHDRAW_MANAGER | | Sepolia | sPOL | SEPOLIA_SPOL | | Sepolia | sPOLController | SEPOLIA_SPOL_CONTROLLER | | Sepolia | sPOLMessenger | SEPOLIA_SPOL_MESSENGER | | Sepolia | polBridger | SEPOLIA_POL_BRIDGER | | Sepolia | rootChainManager | SEPOLIA_ROOT_CHAIN_MANAGER | | Sepolia | stakeManager | SEPOLIA_STAKE_MANAGER | | Sepolia | validatorShare | SEPOLIA_VALIDATOR_SHARE | | Sepolia | withdrawManager | SEPOLIA_WITHDRAW_MANAGER | | Polygon | sPOLChild | POLYGON_SPOL_CHILD | | Polygon | polBridger | POLYGON_POL_BRIDGER | | Amoy | sPOLChild | AMOY_SPOL_CHILD | | Amoy | polBridger | AMOY_POL_BRIDGER |