@paperproof/sdk-ts
v0.3.0
Published
TypeScript SDK for the PaperProof protocol on Sui
Maintainers
Readme
PaperProof Protocol TypeScript SDK
Official TypeScript SDK for the PaperProof Protocol on Sui and Walrus.
This SDK helps developers build wallet-signed transactions, read protocol
state, query canonical events, verify Walrus-backed content, and integrate
PaperProof artifact publishing into web apps, dashboards, indexers, scripts,
and AI or agent tooling. For searches such as PaperProof SDK,
PaperProof Protocol SDK, PaperProof TypeScript SDK, or PaperProof Sui
SDK, this repository is the main TypeScript integration layer.
Official Links
- Website: paperproof.site
- Docs: paperproof.site/#/docs/developers/sdk-overview
- Contracts: PaperProofLabs/paperproof-contracts
- App: PaperProofLabs/paperproof-app
- GitHub organization: PaperProofLabs
The SDK is intentionally deployment-adapter based. Contract package IDs and
canonical object IDs live in a PaperProofDeployment object, so future package
upgrades can be supported by adding or selecting a new deployment without
rewriting application code.
Audience and Coverage
This SDK is intended for three overlapping groups:
- End-user PaperProof web apps that need wallet-signed publishing, versioning, commenting, liking, governance participation, and content reads.
- Community developers building publishing tools, explorers, indexers, dashboards, scoring systems, airdrop pipelines, bots, and integrations with academic or software workflows.
- PaperProof Labs and protocol operators building deployment checks, smoke tests, governance tooling, operational scripts, migration helpers, and troubleshooting tools.
The SDK covers the current PaperProof mainnet protocol surface: artifact publishing and versioning, series metadata updates, artifact owner transfer, comment tree management, comment status control, likes and unlikes, proposal creation, voting, proposal resolution/execution, locked-token claims, operator and authority operations, deployment verification, deployment update checks, trusted event filtering, Move abort explanations, coin selection helpers, and Walrus content verification. It also includes the native prompt manifest helpers, prompt registry transaction builder, and the lightweight memory capability registry builder used by Copilot integrations.
It remains a protocol SDK rather than a key manager or hosted backend. Browser apps should use Sui wallet adapters for signing; server-side and operations scripts may provide their own Sui signers. If a future contract upgrade changes Move entrypoint shapes, the SDK should add a new adapter or wrapper while keeping deployment configuration explicit.
For a full interface map, see docs/API.md.
API Layers
- Low-level provider adapters:
GrpcPaperProofProviderandJsonRpcPaperProofProvidernormalize Sui transport differences. - Read-only query APIs:
PaperProofReadClientandPaperProofQueryClientread objects, typed views, dynamic fields, and canonical events. - Transaction builders:
PaperProofTxBuilderbuilds unsigned transactions for browser wallets or custom PTBs. - High-level service APIs:
PaperProofClientandPaperProofTransactionServicecover common Node.js scripts, robust execution, wallet execution wrappers, dry run, and dev inspect. - Errors and utilities: structured errors, Move abort explanations, validation, address/Object ID normalization, coin helpers, and Walrus helpers.
Install
npm install @paperproof/sdk-ts @mysten/suiLicense and Identity
This SDK is licensed under Apache-2.0 to encourage broad integration, experimentation, commercial use, audits, forks, and tooling around PaperProof and Sui. The Apache-2.0 license applies to this SDK code. It does not grant rights to PaperProof trademarks, official status, official deployment authority, protocol governance authority, protected PaperProof contract source, protected official app source, or protected PaperProof documentation and brand materials.
PaperProof Protocol refers to the open protocol layer and official deployed protocol instances. PaperProof Labs refers to the originating team and maintainer of the official interface, SDKs, reference indexer, documentation, and brand identity.
You may use, fork, modify, and redistribute this SDK under Apache-2.0. If you publish a fork, wrapper, or integration, make its modified or unofficial status clear and do not imply endorsement by PaperProof Labs unless separately authorized.
Basic Usage
import {
createPaperProofSDK,
} from '@paperproof/sdk-ts';
const paperproof = createPaperProofSDK({
network: 'mainnet',
transport: 'grpc',
readRetry: { attempts: 6, baseDelayMs: 1500 },
});
const root = await paperproof.read.getRootView();
console.log(root.id, root.paused);
const tx = paperproof.txb.publishPreprint({
title: 'Example Preprint',
abstractText: 'A PaperProof SDK example.',
authors: ['PaperProof Labs'],
keywords: ['paperproof', 'sdk'],
field: 'Computer Science',
license: 'PaperProof Source-Available License',
pageCount: 1n,
contentHash: 'sha256:...',
walrusBlobId: '...',
walrusBlobObjectId: '...',
contentType: 'application/pdf',
seriesMetadata: [{ key: 'source', value: 'sdk' }],
versionMetadata: [{ key: 'format', value: 'pdf' }],
});createPaperProofSDK is the quickest entry point. It returns read, query,
txb, transactions, and client in one object. Advanced integrations can
still instantiate GrpcPaperProofProvider, PaperProofReadClient,
PaperProofQueryClient, PaperProofTxBuilder, and PaperProofClient
directly.
The SDK builds transaction blocks. It does not own private keys and does not sign transactions for browser users. Use Sui wallet adapters or your server-side signing environment to sign and submit.
Network Configuration
MAINNET_DEPLOYMENT contains the current PaperProof mainnet package IDs,
canonical object IDs, and coin types. For custom deployments or future package
upgrades, use createDeployment(MAINNET_DEPLOYMENT, overrides) and pass the
result into the same clients/builders.
The recommended Sui transport is gRPC through GrpcPaperProofProvider.
JsonRpcPaperProofProvider remains available as a compatibility adapter for
older apps while Sui retires JSON-RPC. Core PaperProof clients consume the
PaperProof provider interfaces rather than a specific Sui transport.
Builder inputs are checked against the protocol's public limits before a
transaction is built. The chain remains the source of truth, but SDK-side checks
catch common mistakes such as oversized metadata, duplicate metadata keys,
invalid comment status values, invalid governance payloads, and overlong content
fields earlier in the developer workflow. Required text fields are also
trim-checked, so whitespace-only titles, abstracts, content hashes, Walrus
references, and comments fail locally with InvalidInputError instead of
waiting for an on-chain abort.
The mainnet deployment also includes the prompt registry used for native Copilot prompts:
- prompt registry package:
0x10b9c6e90a896dc3244d047e32724d80de0dc697b5ea12c5fdd8925131ed4c59 - prompt registry object:
0x14ec45eb83bb1b0eb22c7e885c7c71ea05b1e22dd05e3e1107dcef528600b0da
Native Prompt Helpers
Prompt packages are regular PaperProof generic_file artifacts with content
type application/vnd.paperproof.prompt+json. The SDK exports helpers to
validate, encode, decode, and map prompt packages into generic-file publish
inputs:
import {
encodePromptPackage,
promptPackageToGenericFileInput,
} from '@paperproof/sdk-ts';
const pkg = {
schema_version: 1,
app_id: 'paperproof-app',
route_id: 'copilot/global',
role: 'global' as const,
prompt: 'You are PaperProof Copilot...',
};
const bytes = encodePromptPackage(pkg);
const genericFileInput = promptPackageToGenericFileInput(pkg, {
contentHash: 'sha256:...',
walrusBlobId: '...',
walrusBlobObjectId: '...',
});After publishing the prompt package as a generic_file, register the route in
the prompt registry. Use useLatest: true for ordinary updates, or set
useLatest: false with pinnedVersionId for a pinned rollout:
const tx = paperproof.txb.prompts.registerPrompt({
appId: 'paperproof-app',
routeId: 'copilot/global',
seriesId: '0x13c99b4811d9b89fd0decd8e9c713bafd639e6af3401a18043aed7e0270044fb',
useLatest: true,
});Prompt registry writes are lightweight operator actions. The deployed registry
checks the active operator recorded in the official GovernanceVault; it does
not require per-prompt governance proposals.
Copilot Memory Capability Registry
The SDK also includes transaction builders for a lightweight memory capability registry. This registry is only a discovery/index entry: it records that a wallet has enabled a provider such as MemWal for a given app and namespace. It does not store private memory bodies.
const tx = paperproof.txb.memory.createEntry({
appId: 'paperproof-app',
memoryId: 'copilot/profile',
provider: 'memwal',
accountId: '0x...',
artifactCode: 'PaperProof-generic_file-...',
seriesId: '0x...',
namespaceRoot: 'paperproof/copilot',
schemaVersion: 1,
});Each registration creates a separate MemoryEntry object, and the registry
allows at most one active entry per owner wallet and app id. Users create and
update their own MemWal pointer, while the active operator can set provider
policy, entry availability, and the recommended descriptor version. This path
does not grant PaperProof custody over private memory content.
Users can also tombstone their own entry with
paperproof.txb.memory.deleteOwnEntry({ entryId }). This disables the official
Copilot entry on chain but does not delete MemWal or Walrus private memory
content.
After submitting with showEvents: true, extract canonical object IDs from
events instead of scraping object changes by hand:
const result = extractPublishResult(txResponse, MAINNET_DEPLOYMENT);
console.log(result.seriesId, result.versionId, result.commentsTreeId, result.likesBookId);For production scripts and frontends, prefer the SDK's robust helpers around Sui execution and Walrus upload instead of hand-rolling retry and response normalization in every app:
import {
buildCoinArgumentCoveringAmount,
checkDeploymentUpdate,
filterCanonicalPaperProofEvents,
formatDeploymentUpdateCheck,
robustBuildAndExecuteTransaction,
readAndVerifyWalrusContent,
robustExecuteTransaction,
robustWalrusWriteBlob,
verifyDeployment,
} from '@paperproof/sdk-ts';
const verification = await verifyDeployment({ client: provider, deployment: MAINNET_DEPLOYMENT });
if (!verification.ok) {
console.error(verification.checks);
throw new Error('PaperProof deployment configuration does not match chain state.');
}
// Also check whether the SDK's bundled deployment constants are older than
// the latest PaperProof Labs deployment manifest. Applications can pass their
// own manifest URL or object when they pin a custom deployment.
const update = await checkDeploymentUpdate({ deployment: MAINNET_DEPLOYMENT });
if (update.status === 'update-available') {
console.warn(formatDeploymentUpdateCheck(update));
}
const execution = await robustExecuteTransaction(provider, signer, tx, 'publish preprint', {
attempts: 4,
baseDelayMs: 1500,
});
// For high-frequency writes to shared or recently-mutated objects, rebuild the
// transaction block between retries so stale object versions are not reused.
const commentExecution = await robustBuildAndExecuteTransaction(
provider,
signer,
() => txb.comments.addOnchainComment({ treeId, content: 'Looks good.' }),
'add comment',
{ attempts: 5, baseDelayMs: 1500 },
);
// Coin helpers can prepare an exact transaction argument from one or many
// owned coin objects without hand-written pagination and merge/split logic.
const voteCoin = await buildCoinArgumentCoveringAmount(
provider,
tx,
signer.toSuiAddress(),
MAINNET_DEPLOYMENT.coinTypes.pprf,
100_000_000_000n,
);
const walrus = await robustWalrusWriteBlob(walrusClient, signer, fileBytes, {
label: 'preprint-v1',
epochs: 10,
fallback: true,
});Dry Run and Dev Inspect
Use PaperProofTransactionService when you need build-only, dry-run,
dev-inspect, wallet execution, or Node.js signer execution behind one API.
import { PaperProofTransactionService } from '@paperproof/sdk-ts';
const txService = new PaperProofTransactionService({ client: provider, signer });
const bytes = await txService.buildBytes(tx, { sender: signer.toSuiAddress(), client: provider });
const dryRun = await txService.dryRun({ transaction: bytes });
const execution = await txService.signAndExecute(tx, 'publish preprint');Error Handling
The SDK exposes structured errors such as InvalidAddressError,
InvalidObjectIdError, EventParseError, WalletNotConnectedError,
InsufficientBalanceError, TransactionBuildError, and
TransactionExecutionError. Chain failures also carry PaperProof-specific
explanations where possible.
import { PaperProofError, isPaperProofError } from '@paperproof/sdk-ts';
try {
await txService.signAndExecute(tx, 'publish preprint');
} catch (error) {
if (isPaperProofError(error)) {
console.error(error.code, error.message, error.suggestion);
console.error(error.details);
}
throw error;
}When a helper such as buildCoinArgumentCoveringAmount cannot find enough SUI,
WAL, PPRF, or another coin type, it throws InsufficientBalanceError with
details.required, details.available, details.coinType, and a user-facing
suggestion. Frontends should surface this directly as a top-up or coin-selection
prompt.
Examples
Minimal copyable examples live in examples/quickstart:
query-example.tswatch-events-example.tsbuild-transaction-example.tsnode-script-example.tsexecute-transaction-example.tsparse-events-example.tsindexer-helper-example.tsbrowser-wallet-example.ts
Live mainnet probes used by PaperProof Labs remain in examples/*.ts; they are
more comprehensive and may send real transactions when explicitly run.
robustExecuteTransaction normalizes JSON-RPC and gRPC response shapes,
retries common transient failures, supports expected-failure probes for smoke
tests, and returns events in the shape consumed by the SDK event parsers.
robustWalrusWriteBlob retries transient Walrus failures and can return a
deterministic local placeholder when an application explicitly chooses
fallback: true. The placeholder is useful for smoke tests and degraded
developer workflows; production publishing should surface fallback status to
users and retry real storage when durable Walrus availability is required.
PaperProofReadClient also accepts the same retry options, which helps absorb
short read-after-write consistency windows after creating objects or dynamic
fields on Sui full nodes.
For scripts and server-side integrations that want a higher-level API, use
PaperProofClient. It keeps PaperProofTxBuilder available as txb, exposes
read, executes with the robust transaction helper, and returns typed results
extracted from PaperProof events:
import { PaperProofClient } from '@paperproof/sdk-ts';
const paperproof = new PaperProofClient({
client: provider,
signer,
deployment: MAINNET_DEPLOYMENT,
execute: { attempts: 4, baseDelayMs: 1500 },
});
const published = await paperproof.publishPreprint({
title: 'Example Preprint',
abstractText: 'A PaperProof SDK example.',
authors: ['PaperProof Labs'],
keywords: ['paperproof'],
field: 'Computer Science',
license: 'MIT',
pageCount: 1,
contentHash: 'sha256:...',
walrusBlobId: '...',
walrusBlobObjectId: '...',
contentType: 'application/pdf',
});
console.log(published.result.seriesId);For browser wallet integrations, see examples/browser-wallet. It uses a Sui
wallet adapter to sign and execute a PaperProof transaction without exposing
private keys to the browser app.
Indexers and scoring jobs should filter events by the configured PaperProof packages and canonical object bindings before trusting them:
const canonical = filterCanonicalPaperProofEvents(txResponse, MAINNET_DEPLOYMENT);For application pages and indexers that need stronger guarantees, use the trust
aware query layer. raw only parses provider output, canonical checks the
deployment/package/event shape, and verified also reads the referenced
PaperProof objects to confirm bindings such as series/version, comment tree,
likes book, and governance proposal ownership. Treat incomplete as unknown
data, not as "no records".
Use canonical for ordinary display feeds. Use verified for statistics,
governance history, rewards, airdrop snapshots, and trusted indexer state. On
those paths, call requireVerifiedPage(page) or assertNoIncomplete(page)
before deriving business state.
const page = await paperproof.query.queryVerifiedEvents({
moveEventType: `${MAINNET_DEPLOYMENT.packages.publishing}::publishing::ArtifactPublishedEvent`,
limit: 25,
includeRejected: true,
});
requireVerifiedPage(page);
for (const report of page.verification ?? []) {
console.log(report.status, report.issues.map((issue) => issue.code));
}For frontends, bots, and light indexers that need live updates, use the Watch API on top of the configured query provider. It polls forward with cursors, dedupes repeated events, and keeps canonical filtering in the SDK instead of spreading it through application code:
const watcher = paperproof.watch.watchCanonicalEvents({
limit: 25,
intervalMs: 5000,
onEvent(event) {
console.log(event.type, event.transactionDigest);
},
onError(error) {
console.warn('PaperProof event watch paused after a query error', error);
},
});
watcher.start();
watcher.stop();Governance watchers use the SDK's canonical governance query helpers, including the original and current governance package IDs, so UIs do not accidentally show an empty voting history after a package upgrade:
const votes = paperproof.watch.watchGovernanceVoteCastEvents({
intervalMs: 5000,
onEvents(events) {
updateVoteTimeline(events);
},
});
votes.start();For ordinary app updates, use the named publishing and comments watchers rather than hand-building Move event type strings:
paperproof.watch.watchArtifactPublishedEvents({
onEvents(events) {
appendExploreRows(events.map((event) => event.parsedJson));
},
}).start();
paperproof.watch.watchCommentAddedEvents({
onEvent(event) {
refreshCommentTree(event.parsedJson.tree_id);
},
}).start();
paperproof.watch.watchVerifiedEvents({
limit: 10,
onEvents(events, page) {
if (page.incomplete?.length) markDataAsIncomplete(page.incomplete);
consumeVerifiedEvents(events);
},
}).start();For Walrus-backed content, the SDK can read a blob and verify the returned bytes against the hash stored in a PaperProof version header:
const version = await read.getVersionView(versionId);
const verified = await readAndVerifyWalrusContent(walrusClient, {
blobId: 'the-walrus-blob-id-from-the-version-header',
contentHash: version.contentHash,
});
if (!verified.verification.ok) {
throw new Error(verified.verification.reason);
}Failed executions throw PaperProofSdkError with structured diagnostics such
as label, sender, digest, the normalized transaction response, and a
human-readable PaperProof explanation when a known Move abort is detected:
import { PaperProofSdkError, formatPaperProofErrorExplanation } from '@paperproof/sdk-ts';
try {
await robustExecuteTransaction(provider, signer, tx, 'add version');
} catch (error) {
if (error instanceof PaperProofSdkError) {
console.error(error.digest);
console.error(formatPaperProofErrorExplanation(error.explanation));
}
throw error;
}Modules
PaperProofTxBuilder: publish, version, metadata, owner transfer, comments, likes, and governance transaction builders.PaperProofTxBuilder.prompts: create the prompt registry and register app route bindings to prompt artifact series.PaperProofTxBuilder.memory: create a memory capability registry and let a wallet register or disable its app/provider memory entry.PaperProofTxBuilder.ops: operator, governance authority, migration, cross-module governance execution, and managed-upgrade transaction builders.PaperProofReadClient: object reads and dynamic-field helpers.PaperProofReadClienttyped views:getRootView,getSeriesView,getVersionView,getCommentsTreeView,getCommentNodeView,getLikesBookView,getProposalView,getGovernanceConfigView,getGovernanceVaultView, andgetFeeManagerView.MAINNET_DEPLOYMENT: current canonical mainnet deployment.extractPublishResult,extractAddVersionResult,extractCommentResult,extractProposalResult: transaction event parsers for frontend and script flows.robustExecuteTransaction,robustWalrusWriteBlob,withRetries,normalizeTransactionResponse, andstringifyForJson: production-oriented helpers for retry, response normalization, expected-failure probes, Walrus fallback, and report serialization.verifyDeploymentandformatDeploymentVerification: startup checks for canonical package/object IDs and registry bindings.explainPaperProofErrorandPaperProofSdkError: Move abort parsing and operator-friendly diagnostics for common PaperProof failures.getAllCoins,getOwnedCoinSummary,selectCoinCovering,buildCoinArgumentCoveringAmount, and related helpers: coin pagination, selection, merge/split argument construction, and transfer helpers.PaperProofClient: high-level build/execute/extract facade for common publishing, comment, like, voting, and operator flows.GrpcPaperProofProviderandJsonRpcPaperProofProvider: transport adapters that let the same PaperProof clients work with Sui gRPC or legacy JSON-RPC clients.filterCanonicalPaperProofEvents,requireCanonicalPaperProofEvent, andexplainUntrustedPaperProofEvents: trusted event filtering for frontends, indexers, scoring, and airdrop jobs.robustWalrusReadBlob,readAndVerifyWalrusContent,sha256Hex, andwalrusReferenceFromVersion: Walrus read and content-hash verification helpers.encodePromptPackage,decodePromptPackage,promptPackageToGenericFileInput, and prompt manifest validators: protocol-native prompt package helpers for Copilot and other app prompts.PROTOCOL_LIMITS, status constants, fee constants, governance constants, and validation helpers.types: typed input and decoded state shapes.
Supported Builders
Publishing:
publishPreprintpublishBlogPostpublishTechnicalReportpublishDatasetpublishSoftwareReleasepublishGenericFileaddPreprintVersionaddBlogPostVersionaddTechnicalReportVersionaddDatasetVersionaddSoftwareReleaseVersionaddGenericFileVersionupdateSeriesMetadatatransferArtifactOwner
Comments and interactions:
comments.addOnchainCommentcomments.addBlobCommentcomments.setTreeStatuscomments.setCommentStatuscomments.likeArtifactcomments.unlikeArtifact
Governance:
governance.createProposalgovernance.createSignalProposalgovernance.voteYesgovernance.voteNogovernance.finalizeProposalgovernance.resolveProposalEarlygovernance.executeProposalgovernance.claimLockedTokens
Operations and governance execution:
ops.setProtocolPausedops.setSeriesStatusops.setFeeRecipientops.setGovernanceAuthorityops.setUpgradeAuthorityops.setCommentsFeeLevelops.nominateOperatorops.acceptOperatorTransferops.cancelOperatorTransferops.executeArtifactTypeEnabledProposalops.executeArtifactFeeLevelProposalops.executeArtifactTypeActivationProposalops.executeCommentsFeeLevelProposalops.executeCancelOperatorTransferProposalops.expirePassedProposalops.migrateGovernanceConfigops.migrateProposalops.migrateGovernanceVaultops.migrateCommentsTreeops.transferTreeOwnerops.registerManagedUpgradeCapops.shareManagedUpgradeCapops.authorizeManagedUpgradeops.commitManagedUpgrade
Some operation flows, especially operator transfer acceptance/cancellation and managed package upgrades, require Sui object references created outside the PaperProof contracts. The SDK wraps the PaperProof Move calls, but callers must still provide the relevant Sui object IDs or transaction arguments.
Upgrade Adaptation
Use createDeployment to adapt to a package upgrade or object migration:
import { MAINNET_DEPLOYMENT, createDeployment } from '@paperproof/sdk-ts';
const upgraded = createDeployment(MAINNET_DEPLOYMENT, {
protocolVersion: 'publishing-v3',
packages: {
publishing: '0x...',
},
});Application code can keep using the same builder and read-client APIs as long as the underlying Move entrypoint shapes remain compatible. If an upgrade changes entrypoint shapes, add a new adapter or wrapper while keeping the deployment record explicit.
Testing
npm install
npm test
npm run typecheck
npm run build
npm run pack:dryTests are offline by default and verify transaction construction, deployment adaptation, metadata encoding, and field parsing. They do not send mainnet write transactions. Optional mainnet integration tests are read-only/build-only and run only when explicitly enabled:
PAPERPROOF_RUN_INTEGRATION=1 npx vitest run test/integration-mainnet.test.tsUseful copyable example checks:
npm run example:query
npm run example:build-tx
npm run example:events
npx tsx examples/quickstart/watch-events-example.ts
npm run example:indexerMainnet write probes are intentionally separate and should only be run with operator-controlled environment variables:
npm run example:mainnet
npm run example:mainnet:run
npx tsx examples/mainnet-four-user-journey.ts --check
npx tsx examples/mainnet-four-user-journey.ts --run --target-tx=88mainnet-four-user-journey.ts uses ADDR_1 through ADDR_4 from the local
PaperProof contracts repository .env, funds the worker accounts with small
temporary SUI/WAL/PPRF balances, simulates publishing, versioning, comments,
blob comments, likes, unlikes, metadata updates, owner transfers, and expected
failure paths, then returns all official PPRF and WAL to ADDR_4. The script
asserts that the official PPRF total is unchanged before and after cleanup.
