Soloraa
SDK reference

@soloraa/sdk

A thin TypeScript client over the Soloraa enclave HTTP API and the on-chain program. Submits structured intents, returns verified results, exposes a streaming surface for long sessions.

Quickstart

installbash
npm install @soloraa/sdk @solana/web3.js
my-agent.tsts
import { SoloraaClient } from "@soloraa/sdk";

const client = new SoloraaClient({
    rpcUrl: "https://api.devnet.solana.com",
    enclaveUrl: "http://127.0.0.1:8080",
    walletPda: "3Kh6Y1aeEE9Ss2wbR5DK24KJTDHJf3SZq7sWJkkzKR6N",
});

const result = await client.execute({
    action: "transfer",
    destination: "B4D6...8nqb",
    amount: 1_000_000n,
});

console.log("confirmed", result.signature, "nonce", result.walletNonce);

Client

The SoloraaClient holds the three endpoints it needs and the wallet it acts on behalf of. The client carries no signing keys — every signature comes from the enclave.

constructorts
new SoloraaClient({
    rpcUrl: string,         // Solana RPC
    enclaveUrl: string,     // /sign-* endpoints
    walletPda: string,      // base58
    relayerKeypair?: Keypair, // optional: pays tx fees + broadcasts
});

execute()

Submit an intent, get a confirmed transaction back. Each action maps to a structured request the enclave can policy-check.

signaturets
client.execute(intent: ExecutionIntent): Promise<ExecutionResult>

type ExecutionIntent =
  | { action: "transfer"; destination: string; amount: bigint }
  | {
      action: "swap";
      protocol: "jupiter";
      inputMint: string;
      outputMint: string;
      amount: bigint;
      constraints?: { maxSlippageBps?: number };
    }
  | {
      action: "lend";
      protocol: "kamino" | "marginfi" | "solend";
      mint: string;
      amount: bigint;
    };

type ExecutionResult = {
    signature: string;       // confirmed tx signature
    walletNonce: number;     // post-execution
    bytesSigned: Uint8Array; // 169-byte SOLORA_INTENT_V2
};

verifyIntent()

Reverse-direction check: given a 169-byte signed intent and the enclave pubkey, confirm it would pass the on-chain verifier. Useful for tooling that observes intents without broadcasting.

signaturets
client.verifyIntent(args: {
    message: Uint8Array;    // 169 bytes
    signature: Uint8Array;  // 64 bytes
    enclavePubkey: string;  // base58
}): Promise<VerifyResult>

type VerifyResult =
  | { ok: true; fields: IntentFields }
  | { ok: false; reason: IntentRejectReason };

stream()

Subscribe to lifecycle events for a long-running agent. The stream yields typed events from each of the seven pipeline stages. Backed by Server-Sent Events.

usagets
for await (const event of client.stream({ runId })) {
    if (event.stage === "verify" && event.error) {
        // typed error code from the on-chain program
        console.error(event.error.code, event.error.name);
    }
}

Errors

On-chain rejections surface as typed errors. Codes match the program's error.rs.

CodeNameMeaning
6000WalletPausedWallet authority has paused execution.
6017EnclaveSignerMismatchEd25519 ix signer ≠ wallet.enclave_signer.
6018IntentNonceMismatchReplay rejected — nonce stale.
6019IntentExpiredSigned intent expiry passed.
6021IntentPayloadMismatchDestination, amount, or accounts altered.
6027TargetProgramNotAllowedCPI target not in allowlist.
6033BlockhashMismatchSlot/hash not in SlotHashes.
6037MeasurementRevokedEnclave measurement revoked by governance.
6045AttestationMeasurementMismatchAttestation cites unknown measurement.
6046AttestationGovernorMismatchAttestation signed by non-governor key.

Deployment

The frontend and SDK both target the same on-chain program. See the repo's deployment runbook for the exact commands to stand up devnet infrastructure.

See the deployment runbook →