@pod-protocol/sdk
Version:
TypeScript SDK for PoD Protocol - AI agent communication on Solana
834 lines (830 loc) • 27.1 kB
JavaScript
import { O as address } from './types-CllXlTfL.js';
import { g as generateKeyPairSigner } from './index.node-MFRNpwTP.js';
import { B as BaseService } from './base-D1CgLXYS.js';
import * as anchor from '@coral-xyz/anchor';
/**
* Program IDL in camelCase format in order to be used in JS/TS.
* Optimized to reduce duplicate code.
*
* Note that this is only a type helper and is not the actual IDL. The original
* IDL can be found at `target/idl/pod_com.json`.
*/
// Constants to eliminate duplicate values
const AGENT_SEED = [97, 103, 101, 110, 116];
const ESCROW_SEED = [101, 115, 99, 114, 111, 119];
const CHANNEL_SEED = [99, 104, 97, 110, 110, 101, 108];
const SYSTEM_PROGRAM_ID = "11111111111111111111111111111111";
const IDL = {
address: "HEpGLgYsE1kP8aoYKyLFc3JVVrofS7T4zEA6fWBJsZps",
metadata: {
name: "podCom",
version: "0.1.0",
spec: "0.1.0",
description: "PoD Protocol (Prompt or Die): AI Agent Communication Protocol",
},
instructions: [
{
name: "createChannel",
discriminator: [37, 105, 253, 99, 87, 46, 223, 20],
accounts: [
{
name: "channelAccount",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: CHANNEL_SEED,
},
{
kind: "account",
path: "creator",
},
{
kind: "arg",
path: "name",
},
],
},
},
{
name: "creator",
writable: true,
signer: true,
},
{
name: "systemProgram",
address: SYSTEM_PROGRAM_ID,
},
],
args: [
{
name: "name",
type: "string",
},
{
name: "description",
type: "string",
},
{
name: "visibility",
type: {
defined: {
name: "channelVisibility",
},
},
},
{
name: "maxParticipants",
type: "u32",
},
{
name: "feePerMessage",
type: "u64",
},
],
},
{
name: "depositEscrow",
discriminator: [226, 112, 158, 176, 178, 118, 153, 128],
accounts: [
{
name: "escrowAccount",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: ESCROW_SEED,
},
{
kind: "account",
path: "channelAccount",
},
{
kind: "account",
path: "depositor",
},
],
},
},
{
name: "channelAccount",
writable: true,
},
{
name: "depositor",
writable: true,
signer: true,
},
{
name: "systemProgram",
address: SYSTEM_PROGRAM_ID,
},
],
args: [
{
name: "amount",
type: "u64",
},
],
},
{
name: "registerAgent",
discriminator: [135, 157, 66, 195, 2, 113, 175, 30],
accounts: [
{
name: "agentAccount",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: AGENT_SEED,
},
{
kind: "account",
path: "signer",
},
],
},
},
{
name: "signer",
writable: true,
signer: true,
},
{
name: "systemProgram",
address: SYSTEM_PROGRAM_ID,
},
],
args: [
{
name: "capabilities",
type: "u64",
},
{
name: "metadataUri",
type: "string",
},
],
},
{
name: "sendMessage",
discriminator: [57, 40, 34, 178, 189, 10, 65, 26],
accounts: [
{
name: "messageAccount",
writable: true,
},
{
name: "senderAgent",
pda: {
seeds: [
{
kind: "const",
value: AGENT_SEED,
},
{
kind: "account",
path: "signer",
},
],
},
},
{
name: "signer",
writable: true,
signer: true,
},
{
name: "systemProgram",
address: SYSTEM_PROGRAM_ID,
},
],
args: [
{
name: "recipient",
type: "pubkey",
},
{
name: "payloadHash",
type: {
array: ["u8", 32],
},
},
{
name: "messageType",
type: {
defined: {
name: "messageType",
},
},
},
],
},
{
name: "updateAgent",
discriminator: [85, 2, 178, 9, 119, 139, 102, 164],
accounts: [
{
name: "agentAccount",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: AGENT_SEED,
},
{
kind: "account",
path: "agent_account.pubkey",
account: "agentAccount",
},
],
},
},
{
name: "signer",
signer: true,
},
],
args: [
{
name: "capabilities",
type: {
option: "u64",
},
},
{
name: "metadataUri",
type: {
option: "string",
},
},
],
},
{
name: "updateMessageStatus",
discriminator: [82, 100, 156, 74, 97, 190, 248, 132],
accounts: [
{
name: "messageAccount",
writable: true,
},
{
name: "recipientAgent",
pda: {
seeds: [
{
kind: "const",
value: AGENT_SEED,
},
{
kind: "account",
path: "signer",
},
],
},
},
{
name: "signer",
signer: true,
},
],
args: [
{
name: "newStatus",
type: {
defined: {
name: "messageStatus",
},
},
},
],
},
{
name: "withdrawEscrow",
discriminator: [81, 84, 226, 128, 245, 47, 96, 104],
accounts: [
{
name: "escrowAccount",
writable: true,
pda: {
seeds: [
{
kind: "const",
value: ESCROW_SEED,
},
{
kind: "account",
path: "channelAccount",
},
{
kind: "account",
path: "depositor",
},
],
},
},
{
name: "channelAccount",
writable: true,
},
{
name: "depositor",
writable: true,
signer: true,
},
{
name: "systemProgram",
address: SYSTEM_PROGRAM_ID,
},
],
args: [
{
name: "amount",
type: "u64",
},
],
},
],
accounts: [
{
name: "agentAccount",
discriminator: [241, 119, 69, 140, 233, 9, 112, 50],
},
{
name: "channelAccount",
discriminator: [140, 232, 26, 78, 89, 26, 17, 244],
},
{
name: "escrowAccount",
discriminator: [36, 69, 48, 18, 128, 225, 125, 135],
},
{
name: "messageAccount",
discriminator: [97, 144, 24, 58, 225, 40, 89, 223],
},
],
errors: [
{
code: 6000,
name: "invalidMetadataUriLength",
msg: "Invalid metadata URI length",
},
{
code: 6001,
name: "unauthorized",
msg: "unauthorized",
},
{
code: 6002,
name: "messageExpired",
msg: "Message expired",
},
{
code: 6003,
name: "invalidMessageStatusTransition",
msg: "Invalid message status transition",
},
],
types: [
{
name: "agentAccount",
type: {
kind: "struct",
fields: [
{
name: "pubkey",
type: "pubkey",
},
{
name: "capabilities",
type: "u64",
},
{
name: "metadataUri",
type: "string",
},
{
name: "reputation",
type: "u64",
},
{
name: "lastUpdated",
type: "i64",
},
{
name: "bump",
type: "u8",
},
{
name: "reserved",
type: {
array: ["u8", 7],
},
},
],
},
},
{
name: "channelAccount",
type: {
kind: "struct",
fields: [
{
name: "creator",
type: "pubkey",
},
{
name: "name",
type: "string",
},
{
name: "description",
type: "string",
},
{
name: "visibility",
type: {
defined: {
name: "channelVisibility",
},
},
},
{
name: "maxParticipants",
type: "u32",
},
{
name: "currentParticipants",
type: "u32",
},
{
name: "feePerMessage",
type: "u64",
},
{
name: "escrowBalance",
type: "u64",
},
{
name: "createdAt",
type: "i64",
},
{
name: "bump",
type: "u8",
},
{
name: "reserved",
type: {
array: ["u8", 7],
},
},
],
},
},
{
name: "channelVisibility",
type: {
kind: "enum",
variants: [
{
name: "public",
},
{
name: "private",
},
],
},
},
{
name: "escrowAccount",
type: {
kind: "struct",
fields: [
{
name: "channel",
type: "pubkey",
},
{
name: "depositor",
type: "pubkey",
},
{
name: "amount",
type: "u64",
},
{
name: "createdAt",
type: "i64",
},
{
name: "bump",
type: "u8",
},
{
name: "reserved",
type: {
array: ["u8", 7],
},
},
],
},
},
{
name: "messageAccount",
type: {
kind: "struct",
fields: [
{
name: "sender",
type: "pubkey",
},
{
name: "recipient",
type: "pubkey",
},
{
name: "payloadHash",
type: {
array: ["u8", 32],
},
},
{
name: "messageType",
type: {
defined: {
name: "messageType",
},
},
},
{
name: "createdAt",
type: "i64",
},
{
name: "expiresAt",
type: "i64",
},
{
name: "status",
type: {
defined: {
name: "messageStatus",
},
},
},
{
name: "bump",
type: "u8",
},
{
name: "reserved",
type: {
array: ["u8", 7],
},
},
],
},
},
{
name: "messageStatus",
type: {
kind: "enum",
variants: [
{
name: "pending",
},
{
name: "delivered",
},
{
name: "read",
},
{
name: "failed",
},
],
},
},
{
name: "messageType",
type: {
kind: "enum",
variants: [
{
name: "text",
},
{
name: "data",
},
{
name: "command",
},
{
name: "response",
},
{
name: "custom",
fields: ["u8"],
},
],
},
},
],
};
const { BN, web3 } = anchor;
class SessionKeysService extends BaseService {
constructor(rpcUrl, programId, commitment) {
super(rpcUrl, programId, commitment);
this.sessions = new Map();
this.wallet = null;
}
setWallet(wallet) {
this.wallet = wallet;
}
ensureWallet() {
if (!this.wallet) {
throw new Error('Wallet not set. Call setWallet() first.');
}
return this.wallet;
}
async sendTransactionWithAnchor(methodName, methodArgs, accounts, signers = []) {
const program = this.ensureInitialized();
// Build the transaction using Anchor's method chaining
let txBuilder = program.methods[methodName](...methodArgs)
.accounts(accounts);
// Add signers if provided
if (signers.length > 0) {
txBuilder = txBuilder.signers(signers);
}
// Execute the transaction
return await txBuilder.rpc({ commitment: this.commitment });
}
/**
* Create a new session key for AI agent interactions
*/
async createSessionKey(config) {
try {
// Generate ephemeral keypair
const sessionKeyPairSigner = await generateKeyPairSigner();
// Create session token account (PDA)
const wallet = this.ensureWallet();
// Generate session token account deterministically using PDA
const [sessionTokenAccount] = web3.PublicKey.findProgramAddressSync([
Buffer.from("session"),
new web3.PublicKey(wallet.publicKey || wallet.address).toBuffer(),
new web3.PublicKey(sessionKeyPairSigner.address).toBuffer(),
], new web3.PublicKey(this.programId));
const sessionTokenAccountAddr = address(sessionTokenAccount.toString());
// Create and send session token transaction
const signature = await this.sendTransactionWithAnchor('createSession', [new BN(config.expiryTime), config.maxUses ? new BN(config.maxUses) : null], {
sessionTokenAccount: sessionTokenAccountAddr,
sessionKey: sessionKeyPairSigner.address,
authority: wallet.publicKey || wallet.address,
systemProgram: address("11111111111111111111111111111112"),
rent: address("SysvarRent111111111111111111111111111111111"),
}, [sessionKeyPairSigner]);
const sessionToken = {
sessionKeyPairSigner,
config,
sessionTokenAccount: sessionTokenAccountAddr,
usesRemaining: config.maxUses,
};
// Store session locally
const sessionId = sessionKeyPairSigner.address;
this.sessions.set(sessionId, sessionToken);
console.log(`Session key created: ${sessionId}`);
console.log(`Transaction: ${signature}`);
return sessionToken;
}
catch (error) {
console.error('Failed to create session key:', error);
throw error;
}
}
/**
* Use a session key to sign a transaction
*/
async useSessionKey(sessionId, instructions) {
const session = this.sessions.get(sessionId);
if (!session) {
throw new Error(`Session key not found: ${sessionId}`);
}
// Validate session is still valid
if (Date.now() > session.config.expiryTime) {
throw new Error('Session key has expired');
}
if (session.usesRemaining !== undefined && session.usesRemaining <= 0) {
throw new Error('Session key has no remaining uses');
}
try {
// Validate instructions are allowed
for (const instruction of instructions) {
if (!this.isInstructionAllowed(instruction, session.config)) {
throw new Error(`Instruction not allowed for this session: ${instruction.programAddress}`);
}
}
// Use session key to execute instructions
const wallet = this.ensureWallet();
const signature = await this.sendTransactionWithAnchor('useSession', [new BN(instructions.length)], {
sessionTokenAccount: session.sessionTokenAccount,
sessionKey: session.sessionKeyPairSigner.address,
authority: wallet.publicKey || wallet.address,
}, [session.sessionKeyPairSigner]);
// Decrement uses
if (session.usesRemaining !== undefined) {
session.usesRemaining--;
}
console.log(`Session transaction sent: ${signature}`);
return signature;
}
catch (error) {
console.error('Failed to use session key:', error);
throw error;
}
}
/**
* Revoke a session key
*/
async revokeSessionKey(sessionId) {
const session = this.sessions.get(sessionId);
if (!session) {
throw new Error(`Session key not found: ${sessionId}`);
}
try {
// Revoke session key
const wallet = this.ensureWallet();
const signature = await this.sendTransactionWithAnchor('revokeSession', [], {
sessionTokenAccount: session.sessionTokenAccount,
authority: wallet.publicKey || wallet.address,
});
// Remove from local storage
this.sessions.delete(sessionId);
console.log(`Session key revoked: ${sessionId}`);
return signature;
}
catch (error) {
console.error('Failed to revoke session key:', error);
throw error;
}
}
/**
* Get all active sessions for current wallet
*/
getActiveSessions() {
const now = Date.now();
const sessions = [];
for (const session of this.sessions.values()) {
if (session.config.expiryTime > now) {
sessions.push(session);
}
}
return sessions;
}
/**
* Create session for AI agent messaging (convenience method)
*/
async createMessagingSession(durationHours = 24) {
const config = {
targetPrograms: [address(this.programId)], // PoD Protocol program
expiryTime: Date.now() + (durationHours * 60 * 60 * 1000),
maxUses: 1000, // Generous limit for AI messaging
allowedInstructions: [
'send_message',
'broadcast_message',
'join_channel',
'leave_channel'
]
};
return this.createSessionKey(config);
}
isInstructionAllowed(instruction, config) {
// Check if the program is allowed
const programAllowed = config.targetPrograms.some(program => {
const programAddr = typeof program === 'string' ? address(program) : program;
const instructionProgramAddr = typeof instruction.programAddress === 'string' ? address(instruction.programAddress) : instruction.programAddress;
return programAddr === instructionProgramAddr;
});
if (!programAllowed) {
return false;
}
// If no specific instructions are specified, allow all for the program
if (!config.allowedInstructions || config.allowedInstructions.length === 0) {
return true;
}
// Decode the instruction name from the discriminator
const instructionDiscriminator = Buffer.from(instruction.data.slice(0, 8));
const allowedInstruction = IDL.instructions.find(ix => Buffer.from(ix.discriminator).equals(instructionDiscriminator));
if (!allowedInstruction) {
return false; // Unknown instruction
}
return config.allowedInstructions.includes(allowedInstruction.name);
}
}
export { IDL as I, SessionKeysService as S };
//# sourceMappingURL=session-keys-nfJQ-zmU.js.map