@arsene/core
The TypeScript SDK wraps the three Anchor programs behind one ergonomic class. It ships with two runtimes: a mock mode (in-memory, deterministic, no chain) for tests and local dev, and a chain mode (Anchor + wallet adapter) for devnet and mainnet.
ArseneAgent
The primary entry point. Construct one per agent you control.
export class ArseneAgent {
readonly pubkey: string;
readonly name: string;
readonly principal: string;
constructor(config: AgentConfig);
pay(to: string, amountLamports: bigint, note?: string): Promise<PaymentResult>;
compromise(): void; // demo/testing helper
isCompromised(): boolean;
revoke(reason?: number): void;
pause(): void;
get masque(): MasqueCredential | null;
get policy(): SerrurePolicy | null;
}AgentConfig
interface AgentConfig {
principal: string; // base58 pubkey of the human/DAO
name?: string;
scopeHash?: `0x${string}`; // default: random
lifespanSeconds?: number; // default: 30 days
policy: PolicyParams; // required — see Serrure docs
}PaymentResult
Every pay() returns a discriminated union. Handle both branches explicitly.
type PaymentResult =
| {
status: 'settled';
txId: string;
publicCommitment: `0x${string}`;
timestamp: number;
}
| {
status: 'rejected';
reason: RejectionReason;
message: string;
timestamp: number;
};
type RejectionReason =
| 'revoked' | 'expired' | 'paused'
| 'exceeds_per_tx' | 'rate_limited'
| 'daily_cap' | 'total_cap'
| 'merchant_not_allowed';Protocol events
The protocol store exposes an event bus. Subscribe to watch credential lifecycle, policy checks, and settlements. Useful for dashboards, alerting, and anomaly detection.
import { protocolStore } from '@arsene/core';
const unsub = protocolStore.subscribe((evt) => {
switch (evt.type) {
case 'payment:settled': /* … */ break;
case 'payment:rejected': /* … */ break;
case 'masque:revoked': /* page the on-call */ break;
case 'policy:paused': /* … */ break;
case 'policy:check': /* evt.passed, evt.reason? */ break;
case 'masque:attested': /* evt.reputation */ break;
case 'masque:issued': /* … */ break;
case 'policy:created': /* … */ break;
}
});
// later: unsub();Framework adapters
Thin wrappers that hand an ArseneAgent instance to the framework's payment hook.
ElizaOS
import { arsenePlugin } from '@arsene/eliza';
const runtime = new AgentRuntime({
plugins: [arsenePlugin({ principal, policy: standardPolicy })],
// ...
});LangGraph
import { withArsene } from '@arsene/langgraph';
const graph = withArsene(baseGraph, {
principal,
policy: enterprisePolicy,
onRejection: async (reason) => {
await notifyPrincipal(reason);
},
});Vercel AI SDK
import { arseneTool } from '@arsene/ai-sdk';
const result = await generateText({
model: openai('gpt-4o'),
tools: {
pay: arseneTool({ agent }), // agent.pay behind a tool-use interface
},
});Mock vs. chain
In mock mode, all state lives in a singleton Map. Tests get deterministic ordering. Demos run in any browser. In chain mode, reads go through Helius-indexed accounts, writes go through the wallet adapter's signTransaction. The .pay() signature is identical; you swap from '@arsene/core/mock' for from '@arsene/core/solana'.