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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@goodsdks/engagement-sdk

v1.0.3

Published

`@goodsdks/engagement-sdk` wraps the on-chain [EngagementRewards](../engagement-contracts/contracts/EngagementRewards.sol) contract so apps can onboard reward programs, generate invite claims, and surface reward history. The package exposes low-level Viem

Readme

GoodDollar Engagement SDK

@goodsdks/engagement-sdk wraps the on-chain EngagementRewards contract so apps can onboard reward programs, generate invite claims, and surface reward history. The package exposes low-level Viem utilities plus an optional Wagmi hook for React projects.

Contract ABIs and deployment artifacts are sourced from @goodsdks/engagement-contracts, which ships the deployment data for development and production on Celo.

Installation

yarn add @goodsdks/engagement-sdk @goodsdks/engagement-contracts viem
# or
npm install @goodsdks/engagement-sdk @goodsdks/engagement-contracts viem

React apps should also add wagmi to use the optional useEngagementRewards hook.

Quick Start (Viem)

import { createPublicClient, http } from "viem"
import { createWalletClient, custom } from "viem"
import {
  EngagementRewardsSDK,
  REWARDS_CONTRACT,
} from "@goodsdks/engagement-sdk"

const publicClient = createPublicClient({
  transport: http("https://forno.celo.org"),
})

const walletClient = createWalletClient({
  transport: custom((window as any).ethereum), // swap with your wallet transport
})

const engagement = new EngagementRewardsSDK(
  publicClient,
  walletClient,
  REWARDS_CONTRACT,
  { cacheStorage: window.localStorage },
)

const pending = await engagement.getPendingApps()
console.log("Apps awaiting approval", pending.length)

Use DEV_REWARDS_CONTRACT when pointing at the development deployment.

Registering and Managing Apps

import { zeroAddress } from "viem"

await engagement.applyApp(appAddress, {
  rewardReceiver: appAddress,
  userAndInviterPercentage: 80,
  userPercentage: 60,
  description: "Gamified savings quests for GoodDollar holders",
  url: "https://quests.goodapp.io",
  email: "[email protected]",
})

await engagement.approve(appAddress)

await engagement.updateAppSettings(appAddress, zeroAddress, 75, 55)

const current = await engagement.getAppInfo(appAddress)
console.log("Registered app meta", current)

Issuing Rewards from Off-Chain Logic

Apps that run their invite or quest logic off-chain can pre-sign claims for users. The SDK helps with the EIP-712 payloads enforced by the contract.

const expirationBlock = (await engagement.getCurrentBlockNumber()) + 2_000n
const claimSig = await engagement.signClaim(
  appAddress,
  inviterAddress,
  expirationBlock,
)

await engagement.nonContractAppClaim(
  appAddress,
  inviterAddress,
  1n, // nonce managed by your server
  userSignature,
  claimSig,
)

Consuming Reward Events

rewardEvents = await engagement.getAppRewardEvents(app, options) walks the chain for RewardClaimed logs, paginating in block batches and optionally caching progress with localStorage (or any StorageLike implementation) to avoid rehydrating the entire history each poll.

Key options:

  • blocksAgo (default 500_000n) constrains how far back the scan starts; set to 0n to resume from cache only.
  • batchSize controls block pagination; reduce to avoid RPC limits when running against small providers.
  • inviter enables server-side filtering via indexed topics, skipping client-side post-processing.
  • cacheKey / disableCache / resetCache fine-tune the persistence behaviour when multiple feeds coexist.

Turning Events into a User Activity Feed

The RewardEvent objects expose the app, user, inviter, and individual reward splits. This enables rich UI features such as invite leaderboards or per-user reward timelines.

import type { RewardEvent } from "@goodsdks/engagement-sdk"

const events = await engagement.getAppRewardEvents(appAddress, {
  blocksAgo: 50_000n, // roughly ~2 days on Celo
})

const feed = events
  .sort((a, b) => Number(b.block - a.block))
  .slice(0, 25)
  .map((event) => ({
    tx: event.tx,
    label:
      `${event.user} earned ${event.userAmount} G$` +
      (event.inviterAmount > 0n
        ? ` (inviter ${event.inviter} received ${event.inviterAmount} G$)`
        : ""),
  }))

console.table(feed)

For dashboards that refresh frequently, pass a custom cacheStorage (e.g. Redis, file-backed store) so the SDK can persist the last processed block and fetch only new events. Pair the feed with getAppRewards to highlight aggregate totals alongside the timeline.

React Usage

The package exports a simple Wagmi hook for apps that already provide usePublicClient and useWalletClient context:

import { useEffect, useState } from "react"
import {
  useEngagementRewards,
  REWARDS_CONTRACT,
} from "@goodsdks/engagement-sdk"

const RewardsPanel = () => {
  const sdk = useEngagementRewards(REWARDS_CONTRACT, { debug: true })
  if (!sdk) return <p>Wallet not connected.</p>

  // When the hook resolves, render live stats
  const [stats, setStats] = useState()
  useEffect(() => {
    void sdk.getAppRewards(appAddress).then(setStats)
  }, [sdk])

  return <pre>{JSON.stringify(stats, null, 2)}</pre>
}

API Highlights

  • new EngagementRewardsSDK(publicClient, walletClient, contract, options?)
    • options.cacheStorage lets you plug in localStorage, Expo SecureStore, Redis, etc.
    • options.debug enables verbose logging around RPC batches and cache I/O.
  • applyApp, approve, updateAppSettings
    • Wrap the core registration lifecycle enforced by the EngagementRewards contract.
  • getAppliedApps, getPendingApps, getRegisteredApps
    • Convenience helpers that flatten the contract outputs.
  • nonContractAppClaim, signClaim, prepareClaimSignature
    • Assist with signature-based claims for off-chain reward engines.
  • getAppRewardEvents(app, options)
    • Streams reward history; combine with GetAppRewardEventsOptions to tailor pagination, caching, or inviter scoping.
  • getAppHistory, getAppRewards
    • Fetch historical metadata changes and aggregate reward totals to accompany event feeds.

Type definitions (RewardEvent, AppInfo, AppEvent, etc.) are exported from the package for downstream typing.

Contract Reference

  • Source: packages/engagement-contracts/contracts/EngagementRewards.sol
  • Deployment addresses: @goodsdks/engagement-contracts/ignition/deployments
  • ABI generation command: yarn workspace @goodsdks/engagement-contracts export-abis

When GoodProtocol ships new deployments, regenerate the ABIs and bump this SDK so the helpers stay aligned with the on-chain schema.