Skip to content

TypeScript SDK For Smart Contracts

This page explains the TypeScript SDK helpers for smart contract publishing, calling, inspection, and package automation. It focuses on what the SDK builds and submits.

For the deployment workflow and release evidence, use:

SDK Boundary

The SDK imports protocol definitions from:

text
src/protocol/public-api.ts

That file re-exports transaction types, payload schemas, envelope types, hash helpers, and signing helpers from the core chain modules. This keeps the SDK aligned with the executor and avoids duplicate payload definitions.

Helper Map

GoalSDK helperTransaction or API
Hash WASM byteshashContractCode(...)local helper
Hash a manifesthashContractManifest(...)local helper
Build a manifest objectcontractManifest(...), contractMethod(...)local helper
Deploy codeclient.contracts.deployCode(...)transaction DEPLOY_CONTRACT_CODE
Instantiate a contractclient.contracts.instantiate(...)transaction INSTANTIATE_CONTRACT
Publish loose WASM and manifestclient.contracts.publish(...)transactions DEPLOY_CONTRACT_CODE and INSTANTIATE_CONTRACT
Grant contract bucket accessclient.contracts.grantBucketAccess(...)transaction GRANT_CONTRACT_BUCKET_ACCESS
Call a methodclient.contracts.call(...)transaction CALL_CONTRACT
Deactivate a contractclient.contracts.deactivate(...)transaction DEACTIVATE_CONTRACT
Load a package from diskloadContractPackageFromDirectory(...)Node.js filesystem helper
Publish a packageclient.contracts.publishPackage(...)transactions DEPLOY_CONTRACT_CODE and INSTANTIATE_CONTRACT
Register a packageclient.contracts.registerPackage(...)transaction REGISTER_CONTRACT_PACKAGE
Update package statusclient.transactions.updateContractPackageStatus(...)transaction UPDATE_CONTRACT_PACKAGE_STATUS
Read ABIclient.contracts.abi(...)GET /contracts/{contractId}/abi
Read call resultclient.contracts.callResult(...)receipt API
Query eventsclient.contracts.events(...)event query API
Inspect metricsclient.observability.contracts(...)operator API

Build A Manifest

Use contractManifest(...) when TypeScript code or deployment automation needs to build the manifest object before hashing or publishing.

ts
import { contractManifest } from "@nooschain/client";

const manifest = contractManifest({
  name: "report-store",
  version: "0.1.0",
  runtime: "wasm-assemblyscript-v1",
  methods: {
    saveReport: {
      entrypoint: "saveReport",
      maxFuel: 250000,
      invoke: {
        allow: [{ principalType: "organization", principalId: "org-noos" }],
      },
      buckets: [],
      abi: {
        description: "Store a report and emit report.saved.",
        input: {
          type: "object",
          properties: {
            reportId: { type: "string" },
            status: {
              type: "string",
              enum: ["draft", "submitted", "approved", "rejected"],
            },
            score: { type: "integer" },
          },
          required: ["reportId", "status", "score"],
        },
        output: {
          type: "object",
          properties: { ok: { type: "boolean" } },
          required: ["ok"],
        },
        events: [
          {
            topic: "report.saved",
            schema: {
              type: "object",
              properties: {
                reportId: { type: "string" },
                status: { type: "string" },
              },
              required: ["reportId", "status"],
            },
          },
        ],
      },
    },
  },
});

The manifest hash changes when method ABI, authorization, bucket declarations, calls, migrations, runtime, or other canonical manifest fields change. For field-by-field manifest guidance, see Manifests.

Publish Loose WASM And Manifest

client.contracts.publish(...) is a convenience helper for deployments where automation already has WASM bytes and a manifest object.

ts
import {
  NooschainClient,
  PemTransactionSigner,
  contractManifest,
} from "@nooschain/client";

const client = new NooschainClient({ baseUrl: "http://127.0.0.1:3000" });
const signer = new PemTransactionSigner({ publicKey, privateKeyPem });

const publish = await client.contracts.publish({
  signer,
  nonce: "auto",
  submit: true,
  code: wasmBytes,
  contractId: "contract-report-store",
  manifest,
  ownerUserId: "user-admin",
  organizationId: "org-noos",
});

console.log(publish.deploy.transaction.hash);
console.log(publish.instantiate.transaction.hash);

The helper builds transaction DEPLOY_CONTRACT_CODE and transaction INSTANTIATE_CONTRACT. With submit: true, it submits both transactions. With submit: false, it returns the signed transactions so callers can review, store, or submit them later.

Use the lower-level helpers when you need separate control over each step:

  • client.contracts.deployCode(...);
  • client.contracts.instantiate(...);
  • client.transactions.deployContractCode(...);
  • client.transactions.instantiateContract(...).

For the recommended release workflow, see Publishing.

Publish A Contract Package

Use packages when you want repeatable artifacts instead of loose WASM and manifest values. The SDK can load, validate, hash, and publish a package.

ts
import { loadContractPackageFromDirectory } from "@nooschain/client";

const contractPackage = await loadContractPackageFromDirectory(
  "apps/noos-contract-sdk-as/examples/typed-report-contract/package",
);

const publish = await client.contracts.publishPackage({
  signer,
  nonce: "auto",
  submit: true,
  package: contractPackage,
  contractId: "contract-typed-report",
  ownerUserId: "user-admin",
  organizationId: "org-noos",
  bucketAccess: [
    {
      bucketId: "reports",
      permissions: ["bucket:read_metadata"],
    },
  ],
});

loadContractPackageFromDirectory(...) is available from the Node.js entrypoint because it reads files from disk. Browser clients can use shared descriptor validation helpers, but they cannot load package directories from local paths.

publishPackage(...) builds transaction DEPLOY_CONTRACT_CODE and transaction INSTANTIATE_CONTRACT. If the package includes provenance/signatures.json, the helper can attach package provenance to the instantiate payload.

The package, descriptor, signature, and policy rules are documented in Packages And Provenance and Package Provenance.

Local Signature Preflight

publishPackage(...) accepts signaturePolicy as a local SDK preflight. It is useful when a tool wants to fail before submission if a loaded package is not signed by an expected actor.

ts
await client.contracts.publishPackage({
  signer,
  nonce: "auto",
  submit: true,
  package: contractPackage,
  contractId: "contract-typed-report",
  ownerUserId: "user-admin",
  organizationId: "org-noos",
  signaturePolicy: {
    requireSignature: true,
    allowedSignerTypes: ["user"],
    allowedSignerIds: ["user-admin"],
  },
});

This SDK preflight is not the network authority. Validators enforce the active chain provenance policy during transaction INSTANTIATE_CONTRACT. For policy setup and deterministic rejection behavior, see Package Provenance.

Call A Contract

Use client.contracts.call(...) to build transaction CALL_CONTRACT.

ts
const call = await client.contracts.call({
  signer,
  nonce: "auto",
  contractId: "contract-report-store",
  method: "saveReport",
  args: {
    reportId: "report-001",
    status: "submitted",
    score: 97,
  },
});

await client.transactions.submit(call.transaction);

The SDK signs the transaction envelope. The contract runtime executes the call only after the transaction is included and validated by the chain.

Read ABI

Contracts can expose ABI metadata through their manifest. Fetch deployed ABI with:

ts
const abi = await client.contracts.abi("contract-report-store");
const saveReport = abi.methods.saveReport;

console.log(saveReport.input);
console.log(saveReport.events.map((event) => event.topic));

The HTTP endpoint is:

text
GET /contracts/{contractId}/abi

Legacy methods without ABI metadata return input: null, output: null, and events: [].

Read Call Results

Successful contract calls can store one structured JSON return value as a deterministic execution receipt. Fetch it after transaction CALL_CONTRACT is included and executed:

ts
const result = await client.contracts.callResult(call.transaction.hash);

console.log(result.returnValue);
console.log(result.fuelUsed);

The same receipt is also available as transaction.contractResult in client.transactions.get(hash) after execution.

Query Contract Events

Use event queries for activity feeds, indexers, and transaction diagnostics.

ts
const events = await client.contracts.events({
  contractId: "contract-report-store",
  topic: "report.saved",
  method: "saveReport",
  fromBlock: 10,
  toBlock: 20,
  limit: 25,
});

console.log(events.events[0]?.data);

For a contract-scoped query:

ts
const events = await client.contracts.eventsForContract("contract-report-store", {
  topic: "report.saved",
  order: "desc",
});

Supported filters are contractId, topic, method, transactionHash, fromBlock, toBlock, limit, offset, and order.

Grant Bucket Access

Use client.contracts.grantBucketAccess(...) when a deployed contract principal needs bucket permissions:

ts
await client.contracts.grantBucketAccess({
  signer,
  nonce: "auto",
  submit: true,
  contractId: "contract-report-store",
  bucketId: "reports",
  permissions: ["bucket:read_metadata"],
});

This submits transaction GRANT_CONTRACT_BUCKET_ACCESS. Bucket concepts and permission names are covered in Data Buckets and Permission Model.

Register Packages

The SDK exposes helpers for registry transactions when a network requires registry approval before instantiation.

ts
const registered = await client.contracts.registerPackage({
  signer,
  nonce: "auto",
  package: contractPackage,
  id: "pkg-typed-report-0.1.0",
  auditMetadata: { audits: [{ name: "internal-review", result: "pass" }] },
  approvalMetadata: { approvedFor: "production" },
});

await client.transactions.submit(registered.transaction);

This builds transaction REGISTER_CONTRACT_PACKAGE.

Lower-level helpers are also available:

  • client.transactions.registerContractPackage(...);
  • client.transactions.updateContractPackageStatus(...).

Use Contract Registry for registry status rules, matching fields, and review guidance.

Deactivate Contracts

Use client.contracts.deactivate(...) when a chain admin needs to stop a deployed contract from receiving direct or contract-to-contract calls:

ts
const deactivation = await client.contracts.deactivate({
  signer,
  nonce: "auto",
  submit: true,
  contractId: "contract-report-store",
  reason: "retired vulnerable package",
  metadata: { incidentId: "inc-2026-05-31" },
});

console.log(deactivation.transaction.hash);

This submits transaction DEACTIVATE_CONTRACT. It requires chain:admin, only works while the contract is active, and leaves a consensus audit trail on the contract row.

Contract Metrics

Operator clients can inspect contract execution metrics through the observability client:

ts
const inventory = await client.observability.contracts();
const detail = await client.observability.contract("contract-report-store");
const failedCalls = await client.observability.contractCalls("contract-report-store", {
  status: "failed",
  fromBlock: 10,
  limit: 25,
});

These endpoints require the operator token. Metrics include calls, failures, fuel used, host calls, event counts, write counts, and runtime errors. They are operator diagnostics, not contract storage.

Tests

Run SDK tests:

powershell
npm run nooschain-ts:test

Run package-level type coverage:

powershell
npm run nooschain-ts:build

Run monorepo type coverage after SDK API changes that may affect other apps:

powershell
npm run typecheck

Next Steps

Audience-first NOOSChain documentation.