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

@suigar/sdk

v2.0.0-beta.10

Published

TypeScript SDK for Suigar v2 Move contracts on Sui.

Readme

@suigar/sdk

TypeScript SDK for building Suigar v2 game transactions on Sui.

Installation

npm install --save @suigar/sdk @mysten/sui @mysten/bcs

Runtime requirements:

  • Node.js >=22
  • ESM project configuration ("type": "module")
  • @mysten/sui v2
  • @mysten/bcs v2

This SDK targets Sui TypeScript SDK 2.0+ only. Follow the official Sui 2.0 migration guide if your app still uses the pre-2.0 client API.

What This Package Exposes

The package ships three public entrypoints:

  • @suigar/sdk for the extension factory and runtime client class
  • @suigar/sdk/games for game-specific public types
  • @suigar/sdk/utils for public parser, constants, and numeric helpers

The package root exposes the extension factory and client class:

import { suigar, SuigarClient } from '@suigar/sdk';

It does not export the individual transaction builders from the package root. Those stay on the registered extension instance under client.suigar.tx.

Utility exports are available from the utils subpath:

import {
	DEFAULT_GAS_BUDGET_MIST,
	DEFAULT_LIMBO_MULTIPLIER_SCALE,
	DEFAULT_RANGE_SCALE,
	fromMoveFloat,
	fromMoveI64,
	parseCoinType,
	parseGameDetails,
	RANGE_POINT_LIMIT,
	toBigInt,
	toU8,
} from '@suigar/sdk/utils';

Game-specific type exports are available from the dedicated games subpath:

import type {
	BuildCoinflipTransactionOptions,
	BuildCreatePvPCoinflipTransactionOptions,
	CoinSide,
	PvPCoinflipAction,
} from '@suigar/sdk/games';

Current game-type subpath exports:

  • @suigar/sdk/games: CoinSide, PvPCoinflipAction, BuildCoinflipTransactionOptions, BuildLimboTransactionOptions, BuildPlinkoTransactionOptions, BuildRangeTransactionOptions, BuildWheelTransactionOptions, BuildCreatePvPCoinflipTransactionOptions, BuildJoinPvPCoinflipTransactionOptions, BuildCancelPvPCoinflipTransactionOptions

What you actually use at runtime is the registered extension instance:

const client = new SuiGrpcClient({ baseUrl, network }).$extend(suigar());

client.suigar.serializeTransactionToBase64(...);
client.suigar.getConfig();
client.suigar.getPvPCoinflipGames(...);
client.suigar.bcs;
client.suigar.tx;

Quick Start

import { SuiGrpcClient } from '@mysten/sui/grpc';
import { suigar } from '@suigar/sdk';

const client = new SuiGrpcClient({
	baseUrl: 'https://fullnode.testnet.sui.io:443',
	network: 'testnet',
}).$extend(suigar());

const tx = client.suigar.tx.createBetTransaction('coinflip', {
	playerAddress: '0x123',
	coinType: '0x2::sui::SUI',
	stake: 1_000_000_000n,
	side: 'heads',
});

const base64 = await client.suigar.serializeTransactionToBase64(tx);

Extension Registration

suigar(options?)

Creates a named Sui client extension. By default, it registers under client.suigar.

Partner Setup

Important: partner is the partner wallet address. Configure it once when you register the extension so the SDK can prepend that wallet address to supported bet metadata automatically.

const client = new SuiGrpcClient({ baseUrl, network }).$extend(
	suigar({ partner: '0xpartner_wallet_address' }),
);

client.suigar;

Do not pass a partner slug, label, or display name here. Use the wallet address that should receive partner attribution onchain.

You can rename the extension:

const client = new SuiGrpcClient({ baseUrl, network }).$extend(
	suigar({ name: 'games' }),
);

client.games.tx;
client.games.bcs;

Config

suigar(options?) resolves config from:

  • internal package ids by network
  • internal supported coin types by network
  • internal price info object ids by network
  • the connected client network
  • the extension name

Supported override areas:

  • name
  • partner

If partner is configured, the SDK automatically writes that partner wallet address into the onchain metadata vec-map. Transaction builder options may also include metadata, but reserved keys such as partner and referrer are ignored with a warning when provided manually.

Runtime Surface

The registered extension instance exposes the main runtime surface:

  • getConfig()
  • serializeTransactionToBase64(transaction, options?)
  • getPvPCoinflipGames(options?)
  • bcs
  • tx

getConfig()

Returns the resolved SDK configuration for the connected network.

This is intended mainly for debugging and inspection, for example to verify the resolved package ids or supported coin mappings for the active client network.

It includes:

  • packageIds
  • registryIds
  • coinTypes
  • priceInfoObjectIds
const config = client.suigar.getConfig();
console.log(config.packageIds);

serializeTransactionToBase64(transaction, options?)

Builds a transaction with the configured Sui client and returns base64-encoded transaction bytes.

Use this when you need a transport-safe payload for a wallet, API, or external signer.

const base64 = await client.suigar.serializeTransactionToBase64(tx);

getPvPCoinflipGames(options?)

Lists unresolved PvP coinflip games from the configured PvP registry.

This reads the registry dynamic fields for the active network and resolves each entry into parsed game state through a bulk client.core.getObjects() lookup. Registry membership is the unresolved-state signal: once a match is joined and resolved, the Move flow removes it from the registry and deletes the live Game object.

Use this when a product needs the current set of open PvP coinflip matches for browsing or lobby views.

By default, per-object fetch or parse failures are skipped so one broken or already-deleted registry entry does not reject the full lookup. Pass throwOnError: true if you want the call to reject instead.

Any supported listDynamicFields() options such as limit, cursor, or signal can be passed through options.

const games = await client.suigar.getPvPCoinflipGames({ limit: 20 });

for (const game of games) {
	console.log(game.id);
	console.log(game.coinType);
}
const games = await client.suigar.getPvPCoinflipGames({
	limit: 20,
	throwOnError: true,
});

tx

Transaction builders live under client.suigar.tx.

Standard Games

Use createBetTransaction(gameId, options) for:

  • coinflip
  • limbo
  • plinko
  • range
  • wheel
const tx = client.suigar.tx.createBetTransaction('coinflip', {
	playerAddress: '0x123',
	coinType: '0x2::sui::SUI',
	stake: 1_000_000_000n,
	side: 'tails',
});

Shared option shape:

  • playerAddress: string
  • coinType: string
  • stake: number | bigint
  • cashStake?: number | bigint
  • betCount?: number | bigint
  • metadata?: Record<string, string | number | boolean | bigint | Uint8Array | number[] | null | undefined>
  • gasBudget?: number | bigint
  • allowGasCoinShortcut?: boolean

Shared behavior:

  • stake is the logical stake passed into the Move call
  • cashStake controls the withdrawn balance and defaults to stake
  • betCount defaults to 1
  • metadata is encoded into keys and values byte arrays
  • partner configured via suigar({ partner }) is prepended automatically to metadata as the partner wallet address
  • metadata.partner and metadata.referrer are reserved and ignored with a warning
  • the SDK resolves the price info object from the configured supported-coin mapping
  • the reward object is transferred back to playerAddress

Per-game options:

  • coinflip: side: 'heads' | 'tails'
  • limbo: targetMultiplier: number, scale?: number
  • plinko: configId: number
  • range: leftPoint: number, rightPoint: number, outOfRange?: boolean, scale?: number
  • wheel: configId: number

Examples:

const limboTx = client.suigar.tx.createBetTransaction('limbo', {
	playerAddress: '0x123',
	coinType: '0x2::sui::SUI',
	stake: 1_000_000_000n,
	targetMultiplier: 2.5,
});

const rangeTx = client.suigar.tx.createBetTransaction('range', {
	playerAddress: '0x123',
	coinType: '0x2::sui::SUI',
	stake: 1_000_000_000n,
	leftPoint: 25,
	rightPoint: 75,
	outOfRange: false,
});

Note:

  • limbo converts targetMultiplier with Math.round(targetMultiplier * scale)
  • with the default limbo scale 100, exposed as DEFAULT_LIMBO_MULTIPLIER_SCALE, a target multiplier of 2.5 becomes 250 onchain
  • range converts each point with Math.round(value * scale)
  • range points are bounded by the contract limit exposed as RANGE_POINT_LIMIT
  • with the default range scale 1_000_000, exposed as DEFAULT_RANGE_SCALE, valid UI values are 0 to 100
  • plinko and wheel configId must fit in u8

Tip:

  • if you set scale to 10_000_000, valid UI values become 0 to 10
  • do not pre-scale range points before passing them to the SDK; pass the human value and let the SDK scale it once

PvP Coinflip

Use createPvPCoinflipTransaction(action, options) for PvP coinflip flows:

  • create
  • join
  • cancel

Create:

const tx = client.suigar.tx.createPvPCoinflipTransaction('create', {
	playerAddress: '0x123',
	coinType: '0x2::sui::SUI',
	stake: 1_000_000_000n,
	side: 'heads',
	isPrivate: false,
});

Join:

const tx = client.suigar.tx.createPvPCoinflipTransaction('join', {
	playerAddress: '0x123',
	coinType: '0x2::sui::SUI',
	gameId: '0xGAME_ID',
});

Cancel:

const tx = client.suigar.tx.createPvPCoinflipTransaction('cancel', {
	playerAddress: '0x123',
	coinType: '0x2::sui::SUI',
	gameId: '0xGAME_ID',
});

Join derives the stake from gameId and uses the configured price info object id for coinType.

PvP shared options:

  • playerAddress: string
  • coinType: string
  • metadata?: Record<string, string | number | boolean | bigint | Uint8Array | number[] | null | undefined>
  • gasBudget?: number | bigint
  • allowGasCoinShortcut?: boolean

Action-specific options:

  • create: stake, side, isPrivate?
  • join: gameId
  • cancel: gameId

bcs

BCS helpers live under client.suigar.bcs.

Current exposed helpers:

  • PvPCoinflipGame
  • BetResultEvent
  • PvPCoinflipGameCreatedEvent
  • PvPCoinflipGameResolvedEvent
  • PvPCoinflipGameCancelledEvent

These are generated Move event decoders. Use them to parse Suigar event payloads from transaction results. The @suigar/sdk/utils subpath also exposes parser helpers for generated BCS values:

  • PvPCoinflipGame parses a PvP coinflip game object's content
  • fromMoveI64(float.exp) converts a generated Move i64 exponent to a JavaScript number
  • fromMoveFloat(float) converts a generated Move Float struct to a JavaScript number
  • parseCoinType(type) extracts the normalized coin type from generic Move object type strings such as PvP coinflip Game<T>
  • parseGameDetails(game_details) decodes BetResultEvent.game_details entries into the expected string, number, and boolean values

Parse PvP Coinflip Game Object Data

Use the generated BCS helper when you want to fetch and parse a game object:

const game = await client.suigar.bcs.PvPCoinflipGame.get({
	client,
	objectId: '0xGAME_ID',
});

console.log(game.json);

Parse Standard Bet Result Data

const executeResult = await client.core.executeTransaction({
	transaction: transactionBytes,
	signatures: [signature],
	include: {
		events: true,
	},
});

const finalResult = await client.core.waitForTransaction({
	result: executeResult,
	include: {
		effects: true,
		events: true,
	},
});

if (finalResult.$kind === 'FailedTransaction') {
	throw new Error(finalResult.FailedTransaction.status.error?.message);
}

console.log(finalResult.Transaction.digest);

const transactionResult = finalResult.Transaction;

const betResults = [];

for (const event of transactionResult.events ?? []) {
	try {
		const decoded = client.suigar.bcs.BetResultEvent.parse(event.bcs);
		betResults.push(decoded);
	} catch {
		// Ignore non-BetResultEvent payloads.
	}
}

Parsed fields include:

  • player
  • coin_type
  • stake_amount
  • unsafe_oracle_usd_coin_price
  • adjusted_oracle_usd_coin_price
  • outcome_amount
  • game_details
  • metadata

game_details and metadata decode as VecMap<string, vector<u8>>-shaped data, so values come back as byte arrays. Use parseGameDetails from @suigar/sdk/utils to decode game_details with the SDK's known game-detail schemas.

import { parseGameDetails } from '@suigar/sdk/utils';

const decoded = client.suigar.bcs.BetResultEvent.parse(event.bcs);
const gameDetails = parseGameDetails(decoded.game_details);

parseGameDetails preserves the onchain keys and only changes the value representation. For example, coinflip details keep keys such as player_bet and coin_outcome; range details keep keys such as roll_value, win, and payout_multiplier.

When the extension is configured with partner, decoded event metadata will contain that partner wallet address under the partner entry.

Important:

  • execute or wait for the transaction with include: { events: true }
  • unwrap the core API union with result.$kind, result.Transaction, and result.FailedTransaction
  • parse emitted events from the unwrapped transaction result
  • use event.bcs for consistent decoding across transports
  • use parseGameDetails(decoded.game_details) instead of hand-decoding standard game detail byte arrays

Tip:

  • waitForTransaction({ result, include: { effects: true, events: true } }) is useful when you want the finalized transaction result before decoding
  • these helpers decode the event payload itself, not a full transaction response

Parse PvP Coinflip Event Data

Use the matching helper for each PvP coinflip event payload found in transactionResult.events:

  • client.suigar.bcs.PvPCoinflipGameCreatedEvent
  • client.suigar.bcs.PvPCoinflipGameResolvedEvent
  • client.suigar.bcs.PvPCoinflipGameCancelledEvent

Development

pnpm --dir packages/sdk build
pnpm --dir packages/sdk typecheck
pnpm --dir packages/sdk test

Example App

This repository includes a Next.js integration playground in apps/playground.

It demonstrates:

  • standard game transactions through client.suigar.tx.createBetTransaction(...)
  • PvP coinflip create, join, and cancel flows through client.suigar.tx.createPvPCoinflipTransaction(...), exposed in the example through a PvP coinflip action selector
  • unresolved PvP lobby browsing through client.suigar.getPvPCoinflipGames(...), including public join cards while disconnected, an optional private-lobby join toggle, and connected-wallet filtering for cancel
  • wallet connection and execution with @mysten/dapp-kit-core and @mysten/dapp-kit-react
  • supported coin selection from client.suigar.getConfig()
  • connected-wallet balance display for each supported coin in the example app
  • privacy badges and copyable PvP game ids in the lobby UI
  • decoding BetResultEvent and PvP events into a persistent event log
  • parsing BetResultEvent.game_details with parseGameDetails

Run it from the repo root with:

pnpm install
pnpm turbo run dev --filter='./apps/playground'