Skip to content

TypeScript SDK

The TypeScript client lives in sdks/typescript/ and publishes as @the-ruby-group/teton. Layouts match the Rust builders byte for byte. Slot and lamport values use bigint.

Terminal window
cd sdks/typescript
bun install
bun run build
import {
TETON_PROGRAM_ID,
PACKET_DATA_SIZE,
PacketTooLargeError,
buildRegisterSignerIx,
buildSessionActionTx,
buildAtomicAttestationTx,
buildVerifyNitroAttestationTx,
deriveSignerPda,
} from "@the-ruby-group/teton";

TETON_PROGRAM_ID is EKfHCTnsbRQfURsdmzkmuoxUx7DVt8WsQ5X7t49ZZZh.

Legacy cluster UDP caps a serialized transaction at 1,232 bytes (PACKET_DATA_SIZE). A raw 1,184-byte SNP report does not fit that envelope once signatures and keys are included.

Standard builders call assertPacketFits / probePacket and throw PacketTooLargeError. Submit SNP Mode A / Mode B on Solana v1 (4,096-byte MTU). Test harnesses import the quarantined *Oversized packers. Do not send those to a live cluster.

try {
const ix = buildRegisterSignerIx(payer, signer, report, expiresSlot, nonceSlot);
} catch (err) {
if (err instanceof PacketTooLargeError) {
// Use a v1 transaction, or switch to Nitro whose COSE document can fit.
}
throw err;
}

buildRegisterSignerIx packs verify_and_register: discriminator + nonce_slot (u64 LE) + 1,184-byte report.

expiresSlot is caller bookkeeping. On-chain TTL is clock.slot + 216_000n (ATTESTATION_TTL_SLOTS).

const ix = buildRegisterSignerIx(
payer,
workloadSigner,
snpReport, // Uint8Array length 1184
0n, // expiresSlot bookkeeping
nonceSlot, // bigint
);
const tx = buildSessionActionTx(
payer,
workloadKeypair,
consumerIx,
recentBlockhash,
);

PDA helpers: deriveSignerPda, deriveUsedNoncePda, derivePolicyRegistryPda, deriveVcekPda. All use PublicKey.findProgramAddressSync.

buildAtomicAttestationTx always packs VERIFY_ATOMIC_WITH_NONCE_DISCRIMINATOR at index 0 and the consumer at index 1 (@spec TETON-SEC-005). requireNonce is true.

const tx = buildAtomicAttestationTx(
payer,
consumerProgramId,
actionHash, // 32 bytes
measurement, // 48 bytes
snpReport, // 1184 bytes
consumerIx,
recentBlockhash,
nonceSlot,
);

Expectation type:

interface AtomicAttestationExpectation {
actionHash: Uint8Array;
expectedMeasurement: Uint8Array;
expectedSigner: Uint8Array | null;
requireNonce: boolean; // default true
tetonIxIndex: number | null;
}

buildVerifyNitroAttestationTx packs verify_nitro_attestation.

Field Layout
Discriminator [107, 76, 178, 169, 215, 146, 23, 95]
mode 0 Mode A, 1 Mode B
nonce_slot u64 LE
expected_action_hash 32 bytes
doc_len u32 LE
document COSE Sign1, doc_len ≤ 4096

Mode A uses attested-signer PDA ["attested_signer", workload_signer]. Mode B uses a dummy attested-signer and a nonce PDA seeded with the action commitment SHA-256(slotHash ‖ actionHash ‖ consumerProgramId). Mode B requires a consumer instruction at index 1.

const tx = buildVerifyNitroAttestationTx(
payer,
workloadSigner,
1, // Mode B
nonceSlot,
actionHash,
coseDocument,
nonce, // 32-byte commitment
recentBlockhash,
consumerIx,
);

CU telemetry ceiling for these paths is 550,000 (@spec TETON-PERF-001).