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

@titon-network/forgeton-sdk

v0.8.1

Published

TypeScript SDK for ForgeTON — shared-security staking pool for TON. Stake automatons, slash, receive AutomatonSync pushes. **TSA AUDITED — zero findings** (https://github.com/titon-network/forgeton/blob/main/tsa-analysis/AUDIT_REPORT.md): 11 symbolic-exec

Downloads

700

Readme

@titon-network/forgeton-sdk

Titon-internal. TypeScript client for ForgeTON. Consumed by sibling titon repos (../kronos/, ../fortuna/, future ../atlas/) and the Automaton operator binary (../automaton/). Published to npm so siblings can pin via SemVer — not a public-developer package.

Audit status

TSA-audited — zero findings. Full report: tsa-analysis/AUDIT_REPORT.md.

| Layer | Result | |---|---| | TSA symbolic execution (@anthropic-ai/skills/ton-smart-contract-audit, v0.5.3) | 0 findings across 11 checkers (5 single-contract + 6 inter-contract: forgeton↔kronos, forgeton→atlas, forgeton→fortuna) | | Manual review against references/vulnerabilities.md | every receiver, every revert path | | Contract test suite (pnpm run test) | 262 / 262 passing | | Property fuzz (tests/Fuzz.spec.ts) | 192 random-op iterations × 10 invariants green | | Cross-titon ABI byte-shape pin | tests/WireFormat.spec.ts green | | Coverage caveat | TSA v0.5.3 has a known STIR-opcode coverage gap on Tolk-1.3 storage-write paths; "0 results" is partial evidence rather than exhaustive proof. Compensated by manual review + 262 concrete tests. See report for the honest evidence boundary. | | Third-party audit | Pending. Mainnet is gated on this + a 60-day burn-in (see DEPLOY.md §"Mainnet pilot caps"). |

Live deployment: testnet. The SDK's FORGETON_TESTNET constant tracks the current testnet pool address.

@ton/core is a peer dependency (>= 0.63.0). When developing in-tree the sibling repos pull this via file:../forgeton/sdk and rely on the parent repo's node_modules (do not pnpm install inside sdk/ — see ../CLAUDE.md Debugging table).

Quickstart

npm install @titon-network/forgeton-sdk
# in-tree dev: "@titon-network/forgeton-sdk": "file:../forgeton/sdk" in the sibling's package.json
import { ForgeTON, FORGETON_TESTNET, summarizeTx, formatTxSummary } from '@titon-network/forgeton-sdk';

const pool = tonClient.open(ForgeTON.createFromAddress(FORGETON_TESTNET.forgeton));

const value = await pool.getRegisterValue();
const result = await pool.sendRegisterAutomaton(via, { value });
for (const tx of result.transactions) console.log(formatTxSummary(summarizeTx(tx)));

That's the staker happy path. Owner-side admission, slashing, event decoding, schema verification — see §Task → call below and the examples/ directory.

Surfaces

┌─────────────────────────────────────────────────────────────┐
│ explainError   ForgetonError   summarizeTx   formatTxSummary│  diagnostics
├─────────────────────────────────────────────────────────────┤
│ decodeEvent    decodeEvents    tryDecodeEvent               │  events
├─────────────────────────────────────────────────────────────┤
│ ForgeTON       newPool         FORGETON_DEFAULTS            │  contract + factory
├─────────────────────────────────────────────────────────────┤
│ OP   ERR   loadForgetonCode   FORGETON_TESTNET              │  constants + artifacts
└─────────────────────────────────────────────────────────────┘

Hand-written 1:1 ABI wrapper. No façade, no fluent builder — every titon caller hits the same surface.

Where this SDK is used

| Sibling repo | Touchpoint | Notes | |--------------|-----------|-------| | ../kronos/ | Wraps the pool for owner-side admission scripts; consumer contract embeds the Slash / AutomatonSync wire structs verbatim into its own messages.tolk (no Tolk-level dep). | tests/AbiCompat.spec.ts in kronos guards byte-equivalence. | | ../fortuna/ | Same pattern as Kronos. Consumer wrapper lives in fortuna/sdk/. | Slash on missed BLS fulfillment; ctx = requestId. | | ../atlas/ | Subscribes to AutomatonSync only — never sends Slash. Atlas is fan-out-only. | No slash budget required at admission. | | ../automaton/ | Operator binary — wraps register / unstake / event subscription. | Imports getRegisterValue, getUnstakeValue, event decoder, summarizeTx. | | ../mcp/ | MCP server exposes pool getters as tools. | Read-only surface. |

When ForgeTON's ABI changes (any edit to contracts/messages.tolk or errors.tolk), every consumer above needs the new SDK and (if Tolk wire structs moved) a re-copy of the affected struct. Run pnpm run gen:opcodes first; coordinate the cascade with BLUEPRINT.md in mind.

Task → call (LLM quick reference)

| Task | Call | |------|------| | Deploy a fresh pool | newPool({ owner })pool.sendDeploy(via, toNano('0.5')) | | Admit a titon consumer | pool.sendSetConsumer(ownerVia, { value, contract, isActive: true, maxSlashPerEvent, isOptInRequired }) | | Remove / replace a consumer | Same call with isActive: false. Re-admission resets slash-budget window + opt-in map. | | Tune one consumer's slash cap mid-flight | pool.sendSetConsumerSlashCap(ownerVia, { value, consumer, maxSlashPerEvent }) — preserves window + opt-in map (unlike re-admission). | | Stake an Automaton (gas-scaled to consumer count) | pool.sendRegisterAutomaton(via, { value: await pool.getRegisterValue() }) | | Top up / partial exit | sendIncreaseStake / sendUnstake({ amount, value: await pool.getUnstakeValue({ crossingThreshold: false }) }) | | Full exit | sendRequestUnstake → wait cfg.unstakeCooldownsendUnstake({ amount, value: await pool.getUnstakeValue() }) | | Automaton opt-in / opt-out for a isOptInRequired consumer | sendSetConsumerOptIn / sendSetConsumerOptOut (ops 0x30 / 0x31) — sender = the automaton | | Slash from a consumer (TS-side, mostly tests) | pool.sendSlash(consumerVia, { value, automaton, reason, ctx }) | | Slash from a consumer (Tolk-side, production) | Build Slash { automaton, reason, ctx, amount } (opcode 0x14) and send with SEND_MODE_PAY_FEES_SEPARATELY so the pool's handleSlash gate (msgValue >= MIN_XC_GAS = 0.01 TON) sees the EXACT value attached. SEND_MODE_REGULAR would deduct forward fees from the value and silently shortfall the gate. | | Decode external-out event body | decodeEvent(body) (throws on unknown) / tryDecodeEvent / decodeEvents | | Diagnose any tx | summarizeTx(tx){ success, exitCode, explanation, events, ... } ; formatTxSummary(s) for one-line print | | Pre-validate a config update | ForgeTON.validateConfig(opts) — throws same exit-code as the contract would | | Recover from sync drift | Owner: pool.sendForceSync({ automaton }) — bypasses round-robin cursor | | Propose a code upgrade | sendProposeCodeUpgrade({ newCode, eta }) (absolute) or { newCode, delaySeconds } (relative). Exactly one. ≥ 24 h. | | Verify SDK ↔ on-chain | await pool.getStorageVersion() vs FORGETON_STORAGE_VERSION — or npx forgeton verify --testnet |

Construct + connect

import { ForgeTON, FORGETON_TESTNET, newPool, loadForgetonCode } from '@titon-network/forgeton-sdk';

// Existing testnet pool (most common — siblings + Automaton hit this)
const pool = tonClient.open(ForgeTON.createFromAddress(FORGETON_TESTNET.forgeton));

// Fresh deploy (mainnet, sandbox, replacement testnet)
const pool = tonClient.open(newPool({ owner: ownerAddress }));
//        ≡ ForgeTON.createFromConfig({ owner: ownerAddress }, loadForgetonCode())

// Existing pool by raw address
const pool = tonClient.open(ForgeTON.createFromAddress(addr));

FORGETON_TESTNET carries { owner, forgeton, expectedCodeHash, expectedSchema } — the on-chain snapshot the SDK was built against. Mainnet equivalent lands as FORGETON_MAINNET post-deploy.

Cross-contract ABI (consumer side)

There is no shared Tolk package — every titon consumer embeds the wire structs in its own messages.tolk. The bytes must match forgeton/contracts/messages.tolk exactly:

struct (0x00000014) Slash {
    automaton: address
    reason:    uint32
    ctx:       uint64
}

struct (0x0000001A) AutomatonSync {
    automaton: address
    isActive:  bool
}

If either of these changes here, every consumer repo needs a re-copy. Kronos pins this via tests/AbiCompat.spec.ts; Fortuna does the same. When editing the structs, drive both consumer test suites before merging.

examples/consumer-template.tolk is the reference scaffold — the pattern that Kronos and Fortuna's consumer wrappers followed. Use it when wiring up the next titon consumer (e.g. when Atlas grows a slash path, or for a future product).

Diagnose any tx

import { summarizeTx, formatTxSummary } from '@titon-network/forgeton-sdk';

const result = await pool.sendSlash(via, opts);
for (const tx of result.transactions) {
    const s = summarizeTx(tx);
    console.log(formatTxSummary(s));
    // [ok] events: AutomatonSlashed
    // [fail] exit 160 NotAuthorizedConsumer — Slash sender is not in ForgeTON's consumer set.
    if (!s.success) throw new Error(s.explanation?.hint ?? 'unknown failure');
}

summarizeTx(tx) returns { success, exitCode, actionResultCode, explanation, events, rawExternalBodies } — one call replaces hand-walking compute-phase exit codes, plucking external-out bodies, and decoding each.

Decode events (Argus indexer pattern)

import { decodeEvents } from '@titon-network/forgeton-sdk';

for (const ev of decodeEvents(externalBodies)) {
    switch (ev.kind) {
        case 'AutomatonRegistered':
            console.log(`+ automaton ${ev.automaton} staked ${ev.stake}`);
            break;
        case 'AutomatonSlashed':
            console.warn(`${ev.automaton} slashed -${ev.amount} by ${ev.slasher} (reason=${ev.reason})`);
            break;
        case 'ConsumerUpdated':
            console.log(`consumer ${ev.contract} ${ev.isActive ? 'admitted' : 'removed'} (count=${ev.consumerCount})`);
            break;
    }
}

This is the same decode path Argus uses (titon/argus/PLAN.md). Drift detection lives entirely in Argus — the contract holds no on-chain counters.

Reference

ForgeTON class

1:1 ABI wrapper. send* per inbound op, get* per get fun.

Construct: newPool({ owner, workchain? }) / ForgeTON.createFromConfig({ owner }, code, workchain?) / ForgeTON.createFromAddress(addr).

Send methods:

| Method | Sender | Purpose | |--------|--------|---------| | sendDeploy(via, value) | anyone (deployer) | Initial deploy. Takes value as positional arg (Blueprint convention). | | sendRegisterAutomaton | anyone | Stake. Funded for minStake + minGasForRegister + consumerCount × syncGasCost — use getRegisterValue(). | | sendIncreaseStake | the staked automaton | Top up. | | sendRequestUnstake | the staked automaton | Start cooldown. | | sendCancelUnstake | the staked automaton | Abort cooldown. | | sendUnstake | the staked automaton | Withdraw after cooldown. Cross-zero: minGasForUnstake + consumerCount × syncGasCost — use getUnstakeValue(). | | sendSlash | admitted consumer | Slash. reason: uint32 surfaces in AutomatonSlashed; ctx: uint64 is inbound-only. | | sendSetConsumer | owner | Admit / remove. ≤ MAX_CONSUMERS = 16. | | sendSetConsumerSlashCap | owner | Retune maxSlashPerEvent mid-flight (preserves budget window + opt-in map). | | sendSetConsumerOptIn / sendSetConsumerOptOut | the automaton | Toggle eligibility for an isOptInRequired consumer. | | sendForceSync | owner | Rebroadcast one automaton's state. Cursor-agnostic. | | sendUpdateForgetonConfig | owner | Rewrite the 8-field config blob. Pre-validate with ForgeTON.validateConfig. | | sendWithdrawSlashed | owner | Drain slashed funds. | | sendPruneAutomaton | owner | Emergency-remove a stuck automaton. | | sendPause / sendUnpause | owner | Block new staking. | | sendProposeCodeUpgrade | owner | Pass eta (absolute) or delaySeconds (relative). 24 h floor. | | sendExecuteCodeUpgrade | owner | After eta. | | sendCancelCodeUpgrade | owner | Abort pending. |

Helpers (no I/O for validate*, one-or-two getter calls for get*Value):

| Method | Returns | Notes | |--------|---------|-------| | getRegisterValue() | Promise<bigint> | Live getConfig + getConsumerCount; applies the formula. | | getUnstakeValue({ crossingThreshold }) | Promise<bigint> | true (default) includes fan-out; false for partials. | | ForgeTON.validateConfig(opts) | void (throws) | Local pre-flight matching the contract's lower + upper bounds. Throws ForgetonError with the same exit code the contract would. |

Getters:

| Method | Returns | |--------|---------| | getStorageVersion() | FORGETON_STORAGE_VERSION — verify deployed schema matches SDK | | getOwner() | owner address | | getIsPaused() | pause flag | | getConfig() | full ForgetonConfigReply (8 fields incl. maxSlashPerConsumerPerDay) | | getAutomaton(addr) | AutomatonInfo \| null — throws SchemaDriftError on parse failure | | getIsAutomaton(addr) | boolean | | getActiveAutomatonCount() | active pool size | | getAutomatonCount() | zombie-inclusive count (incl. fully-slashed leftovers) | | getTotalStaked() | sum of all stakes | | getConsumer(addr) | ConsumerInfo \| null (slash-budget window + index) — throws SchemaDriftError | | getIsConsumer(addr) | boolean | | getIsAutomatonOptedIn(consumer, automaton) | boolean — false if either consumer or membership absent | | getConsumerAt(index) | dense lookup in [0, consumerCount) | | getConsumerCount() | admitted consumer count | | getSyncCursor() | round-robin starting index for next pushSync | | getPendingUpgrade() | { codeHash, eta }(0n, 0) when none pending |

Drift / fan-out / slash totals live in Argus (titon/argus/PLAN.md), not on-chain. Argus diffs pool-side AutomatonSync outbounds against each consumer's local syncesReceived getter; owner repairs with sendForceSync({ automaton }).

Events

import { decodeEvent, decodeEvents, tryDecodeEvent } from '@titon-network/forgeton-sdk';

decodeEvent(body)       // throws on unknown opcode — use when source is trusted
tryDecodeEvent(body)    // null on unknown
decodeEvents(bodies)    // batch — silently drops unknowns

Typed discriminated union via event.kind:

AutomatonRegistered    StakeIncreased        UnstakeRequested      UnstakeCancelled
Unstaked               AutomatonSlashed      AutomatonPruned       ForgetonConfigUpdated
ConsumerUpdated        SlashedWithdrawn      PausedChanged         ForceSyncTriggered
ConsumerSlashCapUpdated   AutomatonOptInChanged
UpgradeProposed        UpgradeCancelled      CodeUpdated

AutomatonSlashed carries slasher + reason for attribution. Does NOT carry ctx — correlate by tx hash with the inbound Slash body if you need per-incident context.

Errors

import { explainError, ForgetonError, ERR } from '@titon-network/forgeton-sdk';

const e = explainError(160);
// { code: 160, origin: 'forgeton', name: 'NotAuthorizedConsumer',
//   message: 'Slash sender is not in ForgeTON\'s consumer set.',
//   hint: 'Owner must SetConsumer { contract: <consumer>, isActive: true } before that contract can send Slash.' }

throw new ForgetonError(ERR.NotAuthorizedConsumer, `tx ${txHash}`);

Covers every E_* from contracts/errors.tolk plus common TVM exit codes. Code ranges:

| Range | Owner | |-------|-------| | 0–99 | TVM | | 100–119 | shared admin (NotOwner, Paused, InsufficientGas, BadSchemaVersion) | | 160–179 | ForgeTON staking | | 180–199 | ForgeTON multi-consumer admission | | ≥ 200 | consumer product (Kronos: 100–146 reused per-product; pick distinct ranges) |

Diagnostics

import { summarizeTx, summarizeTxs, formatTxSummary } from '@titon-network/forgeton-sdk';

const s = summarizeTx(tx);
// { success, exitCode, actionResultCode, explanation, events, rawExternalBodies }
formatTxSummary(s);
// '[ok] events: AutomatonSlashed'   |   '[fail] exit 160 NotAuthorizedConsumer — ...'

Accepts any @ton/core Transaction (sandbox BlockchainTransaction works too).

Constants

| Constant | Value | Purpose | |----------|-------|---------| | FORGETON_DEFAULTS | 8-field default config | Default values used at deploy | | FORGETON_STORAGE_VERSION | 1 | Root-storage schema version | | FORGETON_CONFIG_BLOB_VERSION | 1 | Config-blob schema version | | AUTOMATON_INFO_VERSION | 1 | Map-value schema for AutomatonInfo | | CONSUMER_INFO_VERSION | 1 | Map-value schema for ConsumerInfo | | MAX_CONSUMERS | 16 | Hard cap on simultaneous admitted consumers | | MIN_UPGRADE_DELAY_SECONDS | 86400 | 24 h timelock floor | | MAX_UNSTAKE_COOLDOWN | 2592000 | Config ceiling for unstakeCooldown (30 days) | | MIN_SYNC_GAS_COST | toNano('0.01') | Config floor for syncGasCost (= every consumer's MIN_XC_GAS; see §"PAY_FEES_SEPARATELY pushSync" below) | | MAX_SYNC_GAS_COST | toNano('1') | Config ceiling for syncGasCost | | MAX_MIN_STAKE | toNano('10000') | Config ceiling for minStake (pilot 10k TON) | | MAX_MIN_STORAGE_RESERVE | toNano('100') | Config ceiling for minStorageReserve | | MAX_MIN_GAS_PER_OP | toNano('1') | Config ceiling for minGasForRegister and minGasForUnstake | | MAX_SLASH_PER_CONSUMER_PER_DAY | toNano('100000') | Mainnet pilot cap (effective rolling-24h ≤ 100k via token-bucket doubling) | | MIN_XC_GAS | toNano('0.01') | Cross-contract gas floor | | FORGETON_CODE_HASH | { hex, base64 } | Code-hash of the bundled BoC |

Live deployments

import { FORGETON_TESTNET } from '@titon-network/forgeton-sdk';

FORGETON_TESTNET.forgeton            // address
FORGETON_TESTNET.expectedCodeHash    // verify against on-chain
FORGETON_TESTNET.expectedSchema      // hardcoded snapshot

FORGETON_MAINNET lands when the mainnet deploy completes per DEPLOY.md.

Bundled compiled contract

import { loadForgetonCode, FORGETON_CODE_HASH } from '@titon-network/forgeton-sdk';

const code = loadForgetonCode();
// Verify SDK ↔ on-chain alignment:
const liveHash = (await tonClient.getContractState(addr)).codeHash?.toString('hex');
if (liveHash !== FORGETON_CODE_HASH.hex) console.warn('SDK ↔ on-chain code drift');

CLI (npx forgeton)

| Command | Use | |---------|-----| | forgeton explain <code> | Decode an exit code | | forgeton decode <hex> | Decode an external-out event body | | forgeton info <addr> --testnet | Live pool snapshot | | forgeton estimate register --pool <addr> --testnet | Compute the right value: for register | | forgeton verify --testnet | Confirm FORGETON_TESTNET matches the live deploy |

Network commands (info, estimate, verify) need @ton/ton installed (lazy import).

Examples + skills (LLM tooling)

Sandbox-based runnable scripts under examples/ — used as reference scaffolds when wiring up new titon consumers or extending Automaton. skills/ are LLM-invocable task files for the in-tree titon agents.

| Path | What it shows | |------|--------------| | examples/01-deploy-pool.ts | Deploy + verify config + admit a consumer | | examples/02-register-as-automaton.ts | Register, walk full unstake cooldown | | examples/03-slash-from-consumer.ts | Real-counterparty slash via TestConsumer | | examples/04-indexer.ts | Decode events from raw txs (Argus pattern) | | examples/operator-skeleton.ts | Minimal automaton operator — superseded by the Automaton binary; keep as reference | | examples/consumer-template.tolk | Tolk consumer scaffold — the pattern Kronos/Fortuna consumers follow | | skills/ | LLM-invocable task files (titon-internal): integrate-consumer, deploy-pool, run-operator, debug-exit-code, monitor-events |

Versioning

v0.x — on-chain ABI still evolving; SDK majors track contract upgrades. Pin exact versions in sibling repos. When a new schema version ships, increment the matching *_VERSION constant; consumers see SchemaDriftError on getAutomaton / getConsumer until they upgrade.

License

MIT.