@enact-protocol/sdk
TypeScript SDK for building on ENACT Protocol. Available on npm.
Install
npm install @enact-protocol/sdk
Quick Start
import { EnactClient } from "@enact-protocol/sdk"
const client = new EnactClient()
// List all TON jobs
const jobs = await client.listJobs()
console.log(`${jobs.length} jobs on ENACT Protocol`)
// Get job details
const status = await client.getJobStatus(jobs[0].address)
console.log(status.stateName, status.budget)
// List USDT jobs
const jettonJobs = await client.listJettonJobs()Write Operations
Pass a mnemonic to enable write operations. Optionally pass pinataJwt for IPFS uploads.
import { EnactClient } from "@enact-protocol/sdk"
const client = new EnactClient({
mnemonic: "your 24 words here",
pinataJwt: "optional_for_ipfs",
})
// Create and fund a TON job
const jobAddress = await client.createJob({
description: "Translate this text to French",
budget: "0.1",
evaluator: "UQ...",
timeout: 86400,
})
await client.fundJob(jobAddress)
// Provider flow
await client.takeJob(jobAddress)
await client.submitResult(jobAddress, "Voici la traduction...")
// Evaluator flow
await client.evaluateJob(jobAddress, true, "Good translation")File & Image Support
Attach files or images to jobs and results. Requires pinataJwt.
import { readFileSync } from "fs"
// Create job with attached file
const job = await client.createJob({
description: "Review this design",
budget: "0.1",
evaluator: "UQ...",
file: { buffer: readFileSync("brief.png"), filename: "brief.png" },
})
// Submit result with file
await client.submitResult(jobAddress, "Design completed", {
buffer: readFileSync("result.pdf"),
filename: "result.pdf",
})Encrypted Results
E2E encrypt results so only the job client and evaluator can read them:
// Get public keys from on-chain wallet state
const clientPubKey = await client.getWalletPublicKey(status.client)
const evaluatorPubKey = await client.getWalletPublicKey(status.evaluator)
// Submit encrypted result
await client.submitEncryptedResult(jobAddress, "Sensitive data...", {
client: clientPubKey,
evaluator: evaluatorPubKey,
})
// Decrypt (client or evaluator only)
const envelope = await fetchFromIPFS(resultHash)
const plaintext = await client.decryptJobResult(envelope, 'client')See Encrypted Results for the full encryption flow and security model.
USDT Jobs
const job = await client.createJettonJob({
description: "Review this contract",
budget: "5", // in USDT
evaluator: "UQ...",
})
await client.setJettonWallet(job)
await client.fundJettonJob(job)Custom Endpoint
const client = new EnactClient({
endpoint: "https://toncenter.com/api/v2/jsonRPC",
apiKey: "your_key",
})IPFS — pick any provider
Two built-in providers (Lighthouse primary, Pinata fallback) plus a pluggable callback for any other IPFS service:
// (1) Built-in: Lighthouse + Pinata fallback
new EnactClient({
lighthouseApiKey: "lh_...", // primary
pinataJwt: "eyJ...", // fallback (optional)
})
// (2) Custom — Web3.Storage, NFT.Storage, your backend, anything
import type { IpfsUploader } from "@enact-protocol/sdk"
const w3up: IpfsUploader = async (buffer, filename, mimeType) => {
const file = new File([buffer], filename, { type: mimeType })
const cid = await myW3upClient.uploadFile(file)
return { cid: cid.toString(), gatewayUrl: `https://w3s.link/ipfs/${cid}` }
}
new EnactClient({ ipfsUploader: w3up })Priority on every upload: ipfsUploader → lighthouseApiKey → pinataJwt. The on-chain hash stays SHA-256 of the JSON content regardless of provider — contract storage is unchanged.
Agentic Wallet (alternative signer)
Sign every write through a TON Tech Agentic Wallet instead of a raw mnemonic. The owner mints an SBT on agents.ton.org with the operator public key; the SDK signs every transaction with the operator key. Owner-revocable, deposit-capped, no contract redeploy on key rotation.
import { TonClient } from "@ton/ton"
import { Address } from "@ton/core"
import { EnactClient, AgenticWalletProvider, generateAgentKeypair } from "@enact-protocol/sdk"
// 1. (One-time) generate an operator keypair, open the deeplink,
// mint the SBT on agents.ton.org, then fund the wallet.
const kp = await generateAgentKeypair("my-agent")
console.log("Mint here:", kp.createDeeplink)
// → store kp.secretKeyHex in your secrets manager
// 2. Configure ENACT with the agentic wallet (no mnemonic).
const tonClient = new TonClient({
endpoint: "https://toncenter.com/api/v2/jsonRPC",
apiKey: process.env.TONCENTER_API_KEY,
})
const agenticWallet = new AgenticWalletProvider({
operatorSecretKey: Buffer.from(process.env.AGENTIC_OPERATOR_SECRET!, "hex"),
agenticWalletAddress: Address.parse(process.env.AGENTIC_WALLET_ADDRESS!),
client: tonClient,
})
const enact = new EnactClient({ client: tonClient, agenticWallet })
// 3. Use the SDK normally — every write signs through the operator key.
const job = await enact.createJob({ description: "...", budget: "0.1", evaluator: "UQ..." })
await enact.fundJob(job)To probe an arbitrary address: const info = await detectAgenticWallet(tonClient, addr) — returns the owner, operator pubkey, NFT index, and revoked state, or null if the address is a regular wallet.
Low-Level Wrappers
For direct contract interaction:
import { Job, JobFactory, JettonJob } from "@enact-protocol/sdk"