@ghostspeak/sdk
Version:
TypeScript SDK for GhostSpeak AI Agent Commerce Protocol - Production Ready Beta
1,381 lines (1,374 loc) • 52.1 kB
JavaScript
import { TOKEN_PROGRAM_ADDRESS, ASSOCIATED_TOKEN_PROGRAM_ADDRESS, TOKEN_2022_PROGRAM_ADDRESS } from './chunk-HIDBANFS.js';
import { AGENT_DISCRIMINATOR } from './chunk-5QZVFUXB.js';
import { __export } from './chunk-UP2VWCW5.js';
import { fetchEncodedAccount, getProgramDerivedAddress, getBytesEncoder, getAddressEncoder } from '@solana/kit';
import { sha256 } from '@noble/hashes/sha256';
import { randomBytes, bytesToNumberLE, bytesToHex } from '@noble/curves/abstract/utils';
import { ed25519 } from '@noble/curves/ed25519';
// src/utils/discriminator-validator.ts
function validateAccountDiscriminator(accountData, expectedDiscriminator) {
if (accountData.length < expectedDiscriminator.length) {
return {
isValid: false,
expectedLength: expectedDiscriminator.length,
actualLength: accountData.length,
canDecode: false,
needsMigration: true,
errorMessage: `Account too small. Expected at least ${expectedDiscriminator.length} bytes, got ${accountData.length}`
};
}
const actualDiscriminator = accountData.slice(0, expectedDiscriminator.length);
const isValid = actualDiscriminator.every((byte, index) => byte === expectedDiscriminator[index]);
if (isValid) {
return {
isValid: true,
expectedLength: expectedDiscriminator.length,
actualLength: actualDiscriminator.length,
canDecode: true,
needsMigration: false
};
}
if (actualDiscriminator.length >= 2) {
const first2Bytes = actualDiscriminator.slice(0, 2);
if (first2Bytes[0] !== 0 || first2Bytes[1] !== 0) {
return {
isValid: false,
expectedLength: expectedDiscriminator.length,
actualLength: 2,
// Legacy format
canDecode: false,
needsMigration: true,
errorMessage: `Legacy discriminator format detected. Account needs migration.`
};
}
}
return {
isValid: false,
expectedLength: expectedDiscriminator.length,
actualLength: actualDiscriminator.length,
canDecode: false,
needsMigration: true,
errorMessage: `Discriminator mismatch. Expected [${Array.from(expectedDiscriminator).join(", ")}], got [${Array.from(actualDiscriminator).join(", ")}]`
};
}
function createDiscriminatorErrorMessage(validation, accountType, address) {
if (validation.needsMigration) {
return [
`\u26A0\uFE0F ${accountType} account needs attention: ${address}`,
` Issue: ${validation.errorMessage}`,
` Resolution: Account may need to be recreated with current program version`,
` Use 'ghost diagnose account ${address}' for detailed analysis`
].join("\n");
}
if (!validation.canDecode) {
return [
`\u274C Failed to decode ${accountType} account: ${address}`,
` Issue: ${validation.errorMessage}`,
` This may indicate a corrupt or incompatible account`
].join("\n");
}
return `\u2705 ${accountType} account is valid: ${address}`;
}
async function safeDecodeAgent(encodedAccount) {
try {
const { AGENT_DISCRIMINATOR: AGENT_DISCRIMINATOR2, getAgentDecoder } = await import('./agent-S42FIMR7.js');
const validation = validateAccountDiscriminator(encodedAccount.data, AGENT_DISCRIMINATOR2);
if (validation.canDecode) {
try {
const decoder = getAgentDecoder();
const data = decoder.decode(encodedAccount.data);
return { exists: true, data };
} catch (decodeError) {
console.warn(`Failed to decode Agent account ${encodedAccount.address}:`, decodeError);
return { exists: false };
}
}
return { exists: false };
} catch (error) {
console.warn(`Safe decode failed for ${encodedAccount.address}:`, error);
return null;
}
}
function inspectAccountData(encodedAccount, address) {
if (!("exists" in encodedAccount) || !encodedAccount.exists) {
return {
address,
dataLength: 0,
discriminator: null,
discriminatorLength: 0,
isAgentAccount: false,
needsMigration: false,
rawData: new Uint8Array(0)
};
}
const data = "data" in encodedAccount ? encodedAccount.data : new Uint8Array(0);
const discriminatorLength = Math.min(data.length, 8);
const discriminator = discriminatorLength > 0 ? data.slice(0, discriminatorLength) : null;
return {
address,
dataLength: data.length,
discriminator,
discriminatorLength,
isAgentAccount: false,
// Would need more logic to determine this
needsMigration: discriminatorLength > 0 && discriminatorLength < 8,
rawData: data
};
}
// src/utils/account-migration.ts
async function createMigrationPlan(encodedAccount, address) {
const plan = {
address,
currentState: "not_exists",
migrationType: "none",
issues: [],
recommendations: [],
canAutoMigrate: false
};
if (!("exists" in encodedAccount) || !encodedAccount.exists) {
plan.recommendations.push("Account does not exist - no migration needed");
return plan;
}
const { AGENT_DISCRIMINATOR: AGENT_DISCRIMINATOR2 } = await import('./agent-S42FIMR7.js');
const validation = validateAccountDiscriminator(encodedAccount.data, AGENT_DISCRIMINATOR2);
const inspection = inspectAccountData(encodedAccount, address);
if (validation.isValid) {
plan.currentState = "valid";
plan.recommendations.push("Account is already in the correct format");
return plan;
}
if (validation.needsMigration) {
plan.currentState = "needs_migration";
plan.issues.push(`Discriminator length mismatch: expected 8 bytes, got ${validation.actualLength} bytes`);
} else {
plan.currentState = "invalid";
plan.issues.push("Account has invalid or corrupted discriminator");
}
if (inspection.discriminatorLength === 2) {
plan.migrationType = "recreate";
plan.issues.push("Account uses legacy 2-byte discriminator format");
plan.recommendations.push("Recreate account using current register_agent instruction");
plan.recommendations.push("Export existing data first if valuable");
} else if (inspection.discriminatorLength === 0) {
plan.migrationType = "unsupported";
plan.issues.push("Account has no discriminator - may not be an Agent account");
plan.recommendations.push("Verify this is actually an Agent account");
} else if (inspection.discriminatorLength < 8) {
plan.migrationType = "unsupported";
plan.issues.push(`Partial discriminator detected (${inspection.discriminatorLength} bytes)`);
plan.recommendations.push("Account data may be corrupted - consider recreation");
} else {
plan.migrationType = "data_conversion";
plan.issues.push("Discriminator has correct length but wrong values");
plan.recommendations.push("May be from a different program version");
plan.recommendations.push("Check if this account belongs to the correct program");
}
plan.canAutoMigrate = plan.migrationType === "recreate" && inspection.dataLength > 8;
return plan;
}
function extractLegacyData(encodedAccount) {
if (!("exists" in encodedAccount) || !encodedAccount.exists || !("data" in encodedAccount) || encodedAccount.data.length < 2) {
return null;
}
const data = "data" in encodedAccount ? encodedAccount.data : new Uint8Array(0);
try {
if (data.length >= 2) {
return {
discriminator: data.slice(0, 2)
// Add more extraction logic here based on known legacy formats
// This would need to be customized based on actual legacy account structures
};
}
} catch (error) {
console.warn("Failed to extract legacy data:", error);
}
return null;
}
async function createMigrationReport(accounts) {
const plans = await Promise.all(accounts.map(
({ address, encodedAccount }) => createMigrationPlan(encodedAccount, address)
));
const summary = {
total: plans.length,
valid: plans.filter((p) => p.currentState === "valid").length,
needsMigration: plans.filter((p) => p.currentState === "needs_migration").length,
invalid: plans.filter((p) => p.currentState === "invalid").length,
canAutoMigrate: plans.filter((p) => p.canAutoMigrate).length
};
const recommendations = [];
if (summary.needsMigration > 0) {
recommendations.push(`${summary.needsMigration} accounts need migration`);
}
if (summary.canAutoMigrate > 0) {
recommendations.push(`${summary.canAutoMigrate} accounts can be auto-migrated`);
}
if (summary.invalid > 0) {
recommendations.push(`${summary.invalid} accounts have invalid data and should be investigated`);
}
if (summary.needsMigration === 0 && summary.invalid === 0) {
recommendations.push("All accounts are in the correct format");
} else {
recommendations.push("Consider running migration utilities to fix account format issues");
recommendations.push("Backup important account data before migration");
}
return {
summary,
plans,
recommendations
};
}
async function simulateMigration(encodedAccount, address) {
const plan = await createMigrationPlan(encodedAccount, address);
const simulation = {
wouldSucceed: false,
estimatedSteps: [],
warnings: [],
requiredActions: []
};
if (plan.currentState === "valid") {
simulation.wouldSucceed = true;
simulation.estimatedSteps.push("No migration needed - account is already valid");
return { plan, simulation };
}
switch (plan.migrationType) {
case "recreate":
simulation.estimatedSteps.push("1. Extract existing account data");
simulation.estimatedSteps.push("2. Create new account with correct format");
simulation.estimatedSteps.push("3. Transfer any salvageable data");
simulation.estimatedSteps.push("4. Close old account");
simulation.requiredActions.push("User must re-register the agent");
simulation.warnings.push("Some data may be lost during recreation");
simulation.wouldSucceed = plan.canAutoMigrate;
break;
case "data_conversion":
simulation.estimatedSteps.push("1. Analyze existing data format");
simulation.estimatedSteps.push("2. Convert to new format");
simulation.estimatedSteps.push("3. Update discriminator");
simulation.warnings.push("Data conversion is experimental");
simulation.requiredActions.push("Manual verification required");
simulation.wouldSucceed = false;
break;
case "unsupported":
simulation.estimatedSteps.push("1. Manual investigation required");
simulation.estimatedSteps.push("2. Determine if account is recoverable");
simulation.warnings.push("Account may not be recoverable");
simulation.requiredActions.push("Manual inspection and possible recreation");
simulation.wouldSucceed = false;
break;
default:
simulation.estimatedSteps.push("No migration strategy available");
simulation.wouldSucceed = false;
}
return { plan, simulation };
}
function getMigrationInstructions(plan) {
const instructions = [];
switch (plan.migrationType) {
case "none":
instructions.push("\u2705 No migration needed - your account is up to date");
break;
case "recreate":
instructions.push("\u{1F504} Account Recreation Required:");
instructions.push("1. Use the CLI command: `ghost agent register` to create a new account");
instructions.push("2. Configure your agent with the same settings as before");
instructions.push("3. The old account will be automatically replaced");
instructions.push("\u26A0\uFE0F Note: You may need to re-verify your agent after recreation");
break;
case "data_conversion":
instructions.push("\u{1F527} Data Conversion Required:");
instructions.push("1. Contact support for assistance with account conversion");
instructions.push("2. Manual intervention may be required");
instructions.push("3. Backup your account data before proceeding");
break;
case "unsupported":
instructions.push("\u274C Migration Not Supported:");
instructions.push("1. This account cannot be automatically migrated");
instructions.push("2. Consider creating a new account");
instructions.push("3. Contact support if this account contains important data");
break;
}
return instructions;
}
// src/utils/account-diagnostics.ts
var account_diagnostics_exports = {};
__export(account_diagnostics_exports, {
diagnoseAccountFromChain: () => diagnoseAccountFromChain,
diagnoseBatchFromChain: () => diagnoseBatchFromChain,
exportDiagnosticReport: () => exportDiagnosticReport,
runAccountDiagnostics: () => runAccountDiagnostics,
runBatchDiagnostics: () => runBatchDiagnostics
});
async function runAccountDiagnostics(encodedAccount, address) {
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
const accountExists = "exists" in encodedAccount && encodedAccount.exists;
let discriminatorValidation, inspection, migrationPlan, migrationSimulation;
if (accountExists) {
const { AGENT_DISCRIMINATOR: AGENT_DISCRIMINATOR2 } = await import('./agent-S42FIMR7.js');
discriminatorValidation = validateAccountDiscriminator(encodedAccount.data, AGENT_DISCRIMINATOR2);
inspection = inspectAccountData(encodedAccount, address);
migrationPlan = await createMigrationPlan(encodedAccount, address);
migrationSimulation = await simulateMigration(encodedAccount, address);
} else {
discriminatorValidation = {
isValid: false,
actualLength: 0,
expectedLength: 8,
canDecode: false,
needsMigration: false,
errorMessage: "Account does not exist"
};
inspection = {
address,
dataLength: 0,
discriminator: null,
discriminatorLength: 0,
isAgentAccount: false,
needsMigration: false,
rawData: new Uint8Array(0)
};
migrationPlan = {
address,
currentState: "not_exists",
migrationType: "none",
issues: ["Account does not exist"],
recommendations: ["Create account using register_agent instruction"],
canAutoMigrate: false
};
migrationSimulation = {
plan: migrationPlan,
simulation: {
wouldSucceed: false,
estimatedSteps: ["Account must be created first"],
warnings: [],
requiredActions: ["Use register_agent instruction"]
}
};
}
const recommendations = [];
if (!accountExists) {
recommendations.push("Account does not exist - create using register_agent");
} else if (discriminatorValidation.isValid) {
recommendations.push("Account is valid - no action needed");
} else {
recommendations.push(...getMigrationInstructions(migrationPlan));
}
const debugInfo = {
expectedDiscriminator: Array.from(AGENT_DISCRIMINATOR),
actualDiscriminator: inspection.discriminator ? Array.from(inspection.discriminator) : null,
dataPreview: Array.from(inspection.rawData.slice(0, 32)),
programId: accountExists && "owner" in encodedAccount ? encodedAccount.owner : void 0
};
return {
address,
timestamp,
accountExists,
discriminatorValidation,
inspection,
migrationPlan,
migrationSimulation,
recommendations,
debugInfo
};
}
async function runBatchDiagnostics(accounts) {
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
const reports = await Promise.all(accounts.map(
({ address, encodedAccount }) => runAccountDiagnostics(encodedAccount, address)
));
const summary = {
total: reports.length,
valid: reports.filter((r) => r.accountExists && r.discriminatorValidation.isValid).length,
invalid: reports.filter((r) => r.accountExists && !r.discriminatorValidation.isValid).length,
needsMigration: reports.filter((r) => r.migrationPlan.currentState === "needs_migration").length,
notExists: reports.filter((r) => !r.accountExists).length
};
const globalRecommendations = [];
if (summary.notExists > 0) {
globalRecommendations.push(`${summary.notExists} accounts need to be created`);
}
if (summary.needsMigration > 0) {
globalRecommendations.push(`${summary.needsMigration} accounts need migration`);
}
if (summary.invalid > 0) {
globalRecommendations.push(`${summary.invalid} accounts have data issues`);
}
if (summary.valid === summary.total) {
globalRecommendations.push("All accounts are healthy");
}
return {
summary,
reports,
globalRecommendations,
timestamp
};
}
async function diagnoseAccountFromChain(rpc, address, options) {
try {
const encodedAccount = await fetchEncodedAccount(rpc, address);
const report = await runAccountDiagnostics(encodedAccount, address);
if (options?.logToConsole) {
console.group(`\u{1F50D} Account Diagnostics: ${address}`);
console.log("Exists:", report.accountExists);
console.log("Valid:", report.discriminatorValidation.isValid);
console.log("Needs Migration:", report.migrationPlan.currentState === "needs_migration");
console.log("Recommendations:");
report.recommendations.forEach((rec) => console.log(` - ${rec}`));
if (!report.discriminatorValidation.isValid) {
console.log("Issues:");
if (Array.isArray(report.migrationPlan.issues)) {
report.migrationPlan.issues.forEach((issue) => console.log(` - ${issue}`));
}
}
console.groupEnd();
}
return report;
} catch (err) {
console.error(`Failed to diagnose account ${address}:`, err);
return {
address,
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
accountExists: false,
discriminatorValidation: {
isValid: false,
actualLength: 0,
expectedLength: 8,
canDecode: false,
needsMigration: false,
errorMessage: `Failed to fetch account: ${err instanceof Error ? err.message : String(err)}`
},
inspection: {
address,
dataLength: 0,
discriminator: null,
discriminatorLength: 0,
isAgentAccount: false,
needsMigration: false,
rawData: new Uint8Array(0)
},
migrationPlan: {
address,
currentState: "invalid",
migrationType: "unsupported",
issues: [`Failed to fetch account: ${err instanceof Error ? err.message : String(err)}`],
recommendations: ["Check network connection and account address"],
canAutoMigrate: false
},
migrationSimulation: {
plan: {
address,
currentState: "invalid",
migrationType: "unsupported",
issues: [`Failed to fetch account: ${err instanceof Error ? err.message : String(err)}`],
recommendations: ["Check network connection and account address"],
canAutoMigrate: false
},
simulation: {
wouldSucceed: false,
estimatedSteps: ["Fix network connectivity issues"],
warnings: ["Account could not be fetched"],
requiredActions: ["Verify account address and network connection"]
}
},
recommendations: ["Check network connection and account address"],
debugInfo: {
expectedDiscriminator: Array.from(AGENT_DISCRIMINATOR),
actualDiscriminator: null,
dataPreview: [],
programId: void 0
}
};
}
}
async function diagnoseBatchFromChain(rpc, addresses, options) {
const maxConcurrent = options?.maxConcurrent ?? 10;
const reports = [];
for (let i = 0; i < addresses.length; i += maxConcurrent) {
const batch = addresses.slice(i, i + maxConcurrent);
const batchPromises = batch.map(
(address) => diagnoseAccountFromChain(rpc, address, { logToConsole: false })
);
const batchReports = await Promise.allSettled(batchPromises);
for (const result of batchReports) {
if (result.status === "fulfilled") {
reports.push(result.value);
} else {
console.error("Failed to diagnose account:", result.reason);
reports.push({
address: "unknown",
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
accountExists: false,
discriminatorValidation: {
isValid: false,
actualLength: 0,
expectedLength: 8,
canDecode: false,
needsMigration: false,
errorMessage: "Failed to fetch account"
},
inspection: {
address: "unknown",
dataLength: 0,
discriminator: null,
discriminatorLength: 0,
isAgentAccount: false,
needsMigration: false,
rawData: new Uint8Array(0)
},
migrationPlan: {
address: "unknown",
currentState: "invalid",
migrationType: "unsupported",
issues: ["Failed to fetch account"],
recommendations: ["Check network connection"],
canAutoMigrate: false
},
migrationSimulation: {
plan: {
address: "unknown",
currentState: "invalid",
migrationType: "unsupported",
issues: ["Failed to fetch account"],
recommendations: ["Check network connection"],
canAutoMigrate: false
},
simulation: {
wouldSucceed: false,
estimatedSteps: ["Fix fetch issues"],
warnings: ["Account could not be fetched"],
requiredActions: ["Check network"]
}
},
recommendations: ["Check network connection"],
debugInfo: {
expectedDiscriminator: Array.from(AGENT_DISCRIMINATOR),
actualDiscriminator: null,
dataPreview: [],
programId: void 0
}
});
}
}
}
const batchReport = await runBatchDiagnostics(
reports.map((report) => ({
address: report.address,
encodedAccount: {
exists: report.accountExists,
data: report.inspection.rawData,
address: report.address,
owner: report.debugInfo.programId ?? "",
executable: false,
lamports: 0n,
programAddress: report.debugInfo.programId ?? "",
space: report.inspection.rawData.length
}
}))
);
if (options?.logToConsole) {
console.group("\u{1F50D} Batch Diagnostics Summary");
console.log("Total accounts:", batchReport.summary.total);
console.log("Valid accounts:", batchReport.summary.valid);
console.log("Invalid accounts:", batchReport.summary.invalid);
console.log("Need migration:", batchReport.summary.needsMigration);
console.log("Do not exist:", batchReport.summary.notExists);
console.log("Global recommendations:");
batchReport.globalRecommendations.forEach((rec) => console.log(` - ${rec}`));
console.groupEnd();
}
return batchReport;
}
function exportDiagnosticReport(report, filename) {
const json = JSON.stringify(report, null, 2);
if (filename) {
console.log(`Diagnostic report would be saved as: ${filename}`);
console.log("Report data:", json);
}
return json;
}
var TokenProgram = /* @__PURE__ */ ((TokenProgram2) => {
TokenProgram2["SPL_TOKEN"] = "spl-token";
TokenProgram2["TOKEN_2022"] = "token-2022";
return TokenProgram2;
})(TokenProgram || {});
var TokenExtension = /* @__PURE__ */ ((TokenExtension2) => {
TokenExtension2[TokenExtension2["UNINITIALIZED"] = 0] = "UNINITIALIZED";
TokenExtension2[TokenExtension2["TRANSFER_FEE_CONFIG"] = 1] = "TRANSFER_FEE_CONFIG";
TokenExtension2[TokenExtension2["TRANSFER_FEE_AMOUNT"] = 2] = "TRANSFER_FEE_AMOUNT";
TokenExtension2[TokenExtension2["MINT_CLOSE_AUTHORITY"] = 3] = "MINT_CLOSE_AUTHORITY";
TokenExtension2[TokenExtension2["CONFIDENTIAL_TRANSFER_MINT"] = 4] = "CONFIDENTIAL_TRANSFER_MINT";
TokenExtension2[TokenExtension2["CONFIDENTIAL_TRANSFER_ACCOUNT"] = 5] = "CONFIDENTIAL_TRANSFER_ACCOUNT";
TokenExtension2[TokenExtension2["DEFAULT_ACCOUNT_STATE"] = 6] = "DEFAULT_ACCOUNT_STATE";
TokenExtension2[TokenExtension2["IMMUTABLE_OWNER"] = 7] = "IMMUTABLE_OWNER";
TokenExtension2[TokenExtension2["MEMO_TRANSFER"] = 8] = "MEMO_TRANSFER";
TokenExtension2[TokenExtension2["NON_TRANSFERABLE"] = 9] = "NON_TRANSFERABLE";
TokenExtension2[TokenExtension2["INTEREST_BEARING_MINT"] = 10] = "INTEREST_BEARING_MINT";
TokenExtension2[TokenExtension2["CPI_GUARD"] = 11] = "CPI_GUARD";
TokenExtension2[TokenExtension2["PERMANENT_DELEGATE"] = 12] = "PERMANENT_DELEGATE";
TokenExtension2[TokenExtension2["NON_TRANSFERABLE_ACCOUNT"] = 13] = "NON_TRANSFERABLE_ACCOUNT";
TokenExtension2[TokenExtension2["TRANSFER_HOOK"] = 14] = "TRANSFER_HOOK";
TokenExtension2[TokenExtension2["TRANSFER_HOOK_ACCOUNT"] = 15] = "TRANSFER_HOOK_ACCOUNT";
TokenExtension2[TokenExtension2["METADATA_POINTER"] = 16] = "METADATA_POINTER";
TokenExtension2[TokenExtension2["TOKEN_METADATA"] = 17] = "TOKEN_METADATA";
TokenExtension2[TokenExtension2["GROUP_POINTER"] = 18] = "GROUP_POINTER";
TokenExtension2[TokenExtension2["TOKEN_GROUP"] = 19] = "TOKEN_GROUP";
TokenExtension2[TokenExtension2["GROUP_MEMBER_POINTER"] = 20] = "GROUP_MEMBER_POINTER";
TokenExtension2[TokenExtension2["TOKEN_GROUP_MEMBER"] = 21] = "TOKEN_GROUP_MEMBER";
return TokenExtension2;
})(TokenExtension || {});
async function deriveAssociatedTokenAddress(owner, mint, tokenProgram = TOKEN_PROGRAM_ADDRESS) {
const [address] = await getProgramDerivedAddress({
programAddress: ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
seeds: [
getAddressEncoder().encode(owner),
getAddressEncoder().encode(tokenProgram),
getAddressEncoder().encode(mint)
]
});
return address;
}
async function deriveSplTokenAssociatedTokenAddress(owner, mint) {
return deriveAssociatedTokenAddress(owner, mint, TOKEN_PROGRAM_ADDRESS);
}
async function deriveToken2022AssociatedTokenAddress(owner, mint) {
return deriveAssociatedTokenAddress(owner, mint, TOKEN_2022_PROGRAM_ADDRESS);
}
async function getAssociatedTokenAccount(owner, mint, tokenProgram) {
const program = tokenProgram ?? TOKEN_PROGRAM_ADDRESS;
const isToken2022 = program === TOKEN_2022_PROGRAM_ADDRESS;
const address = await deriveAssociatedTokenAddress(owner, mint, program);
return {
address,
owner,
mint,
tokenProgram: program,
isToken2022
};
}
async function detectTokenProgram(mint, rpcEndpoint = "https://api.devnet.solana.com") {
try {
const { createSolanaRpc } = await import('@solana/kit');
const rpc = createSolanaRpc(rpcEndpoint);
const accountInfo = await rpc.getAccountInfo(mint, {
encoding: "base64",
commitment: "confirmed"
}).send();
if (!accountInfo.value) {
throw new Error(`Mint account ${mint} not found`);
}
const ownerProgram = accountInfo.value.owner;
if (ownerProgram === TOKEN_PROGRAM_ADDRESS) {
return TOKEN_PROGRAM_ADDRESS;
} else if (ownerProgram === TOKEN_2022_PROGRAM_ADDRESS) {
return TOKEN_2022_PROGRAM_ADDRESS;
} else {
console.warn(`Unknown token program owner: ${ownerProgram}, defaulting to SPL Token`);
return TOKEN_PROGRAM_ADDRESS;
}
} catch (error) {
console.error(`Failed to detect token program for mint ${mint}:`, error);
return TOKEN_PROGRAM_ADDRESS;
}
}
async function isToken2022Mint(mint) {
const program = await detectTokenProgram(mint);
return program === TOKEN_2022_PROGRAM_ADDRESS;
}
async function getTokenProgramType(mint) {
const isToken2022 = await isToken2022Mint(mint);
return isToken2022 ? "token-2022" /* TOKEN_2022 */ : "spl-token" /* SPL_TOKEN */;
}
async function checkToken2022Extensions(mint, extensions, _rpcEndpoint = "https://api.devnet.solana.com") {
console.warn(`Token-2022 extension checking is deprecated: mint ${mint}`);
const result = {};
for (const extension of extensions) {
result[extension] = false;
}
return result;
}
async function hasTransferFeeExtension(mint, rpcEndpoint = "https://api.devnet.solana.com") {
const result = await checkToken2022Extensions(
mint,
[1 /* TRANSFER_FEE_CONFIG */],
rpcEndpoint
);
return result[1 /* TRANSFER_FEE_CONFIG */];
}
async function hasConfidentialTransferExtension(mint, rpcEndpoint = "https://api.devnet.solana.com") {
const result = await checkToken2022Extensions(
mint,
[4 /* CONFIDENTIAL_TRANSFER_MINT */],
rpcEndpoint
);
return result[4 /* CONFIDENTIAL_TRANSFER_MINT */];
}
async function hasInterestBearingExtension(mint, rpcEndpoint = "https://api.devnet.solana.com") {
const result = await checkToken2022Extensions(
mint,
[10 /* INTEREST_BEARING_MINT */],
rpcEndpoint
);
return result[10 /* INTEREST_BEARING_MINT */];
}
async function getTransferFeeConfig(mint, _rpcEndpoint = "https://api.devnet.solana.com") {
console.warn(`Token-2022 getTransferFeeConfig is deprecated: mint ${mint}`);
return null;
}
async function getConfidentialTransferConfig(mint, _rpcEndpoint = "https://api.devnet.solana.com") {
console.warn(`Token-2022 getConfidentialTransferConfig is deprecated: mint ${mint}`);
return null;
}
async function getInterestBearingConfig(mint, _rpcEndpoint = "https://api.devnet.solana.com") {
console.warn(`Token-2022 getInterestBearingConfig is deprecated: mint ${mint}`);
return null;
}
async function getAllAssociatedTokenAddresses(owner, mint) {
const [splToken, token2022] = await Promise.all([
deriveSplTokenAssociatedTokenAddress(owner, mint),
deriveToken2022AssociatedTokenAddress(owner, mint)
]);
return { splToken, token2022 };
}
async function validateAssociatedTokenAddress(address, owner, mint) {
const addresses = await getAllAssociatedTokenAddresses(owner, mint);
if (address === addresses.splToken) {
return { isValid: true, program: TOKEN_PROGRAM_ADDRESS };
}
if (address === addresses.token2022) {
return { isValid: true, program: TOKEN_2022_PROGRAM_ADDRESS };
}
return { isValid: false };
}
function getTokenProgramAddress(program) {
switch (program) {
case "spl-token" /* SPL_TOKEN */:
return TOKEN_PROGRAM_ADDRESS;
case "token-2022" /* TOKEN_2022 */:
return TOKEN_2022_PROGRAM_ADDRESS;
default:
throw new Error(`Unknown token program: ${program}`);
}
}
function getTokenProgramFromAddress(address) {
if (address === TOKEN_PROGRAM_ADDRESS) {
return "spl-token" /* SPL_TOKEN */;
}
if (address === TOKEN_2022_PROGRAM_ADDRESS) {
return "token-2022" /* TOKEN_2022 */;
}
throw new Error(`Unknown token program address: ${address}`);
}
function formatTokenAmount(amount, decimals) {
const divisor = BigInt(10 ** decimals);
const quotient = amount / divisor;
const remainder = amount % divisor;
if (remainder === BigInt(0)) {
return quotient.toString();
}
const remainderStr = remainder.toString().padStart(decimals, "0");
const trimmedRemainder = remainderStr.replace(/0+$/, "");
return `${quotient}.${trimmedRemainder}`;
}
function parseTokenAmount(formatted, decimals) {
const [whole, fraction = ""] = formatted.split(".");
const paddedFraction = fraction.padEnd(decimals, "0").slice(0, decimals);
const rawAmount = whole + paddedFraction;
return BigInt(rawAmount);
}
// src/utils/governance-helpers.ts
var governance_helpers_exports = {};
__export(governance_helpers_exports, {
GovernanceAnalyticsUtils: () => GovernanceAnalyticsUtils,
PERMISSION_TEMPLATES: () => PERMISSION_TEMPLATES,
ProposalUtils: () => ProposalUtils,
ROLE_TEMPLATES: () => ROLE_TEMPLATES,
VotingUtils: () => VotingUtils,
deriveMultisigPda: () => deriveMultisigPda,
deriveProposalPda: () => deriveProposalPda,
deriveRbacPda: () => deriveRbacPda
});
async function deriveMultisigPda(programId, authority, multisigId) {
const [pda] = await getProgramDerivedAddress({
programAddress: programId,
seeds: [
getBytesEncoder().encode(new Uint8Array([109, 117, 108, 116, 105, 115, 105, 103])),
// 'multisig'
getAddressEncoder().encode(authority),
new Uint8Array(new BigUint64Array([multisigId]).buffer)
]
});
return pda;
}
async function deriveProposalPda(programId, multisig, proposalId) {
const [pda] = await getProgramDerivedAddress({
programAddress: programId,
seeds: [
getBytesEncoder().encode(new Uint8Array([112, 114, 111, 112, 111, 115, 97, 108])),
// 'proposal'
getAddressEncoder().encode(multisig),
new Uint8Array(new BigUint64Array([proposalId]).buffer)
]
});
return pda;
}
async function deriveRbacPda(programId, admin) {
const [pda] = await getProgramDerivedAddress({
programAddress: programId,
seeds: [
getBytesEncoder().encode(new Uint8Array([114, 98, 97, 99])),
// 'rbac'
getAddressEncoder().encode(admin)
]
});
return pda;
}
var ProposalUtils = class {
/**
* Check if proposal is in voting period
*/
static isVotingOpen(proposal) {
const now = BigInt(Math.floor(Date.now() / 1e3));
return proposal.status === 1 /* Active */ && now >= proposal.votingStartsAt && now <= proposal.votingEndsAt;
}
/**
* Check if proposal has expired
*/
static hasExpired(proposal) {
const now = BigInt(Math.floor(Date.now() / 1e3));
return now > proposal.votingEndsAt;
}
/**
* Calculate time remaining for voting
*/
static timeRemaining(proposal) {
const now = BigInt(Math.floor(Date.now() / 1e3));
if (now >= proposal.votingEndsAt) return 0n;
return proposal.votingEndsAt - now;
}
/**
* Format time remaining as human-readable string
*/
static formatTimeRemaining(proposal) {
const remaining = this.timeRemaining(proposal);
if (remaining === 0n) return "Voting ended";
const seconds = Number(remaining);
const days = Math.floor(seconds / 86400);
const hours = Math.floor(seconds % 86400 / 3600);
const minutes = Math.floor(seconds % 3600 / 60);
if (days > 0) return `${days}d ${hours}h remaining`;
if (hours > 0) return `${hours}h ${minutes}m remaining`;
return `${minutes}m remaining`;
}
/**
* Calculate if proposal has reached quorum
*/
static hasReachedQuorum(votingResults, quorumRequirements, totalEligibleVoters) {
const totalVotes = Number(votingResults.votesFor + votingResults.votesAgainst + votingResults.votesAbstain);
const participationRate = totalVotes / totalEligibleVoters * 100;
return participationRate >= quorumRequirements.minimumParticipation;
}
/**
* Calculate voting results summary
*/
static calculateResults(votingResults) {
const total = Number(votingResults.votesFor + votingResults.votesAgainst + votingResults.votesAbstain);
if (total === 0) {
return {
total: 0,
forPercentage: 0,
againstPercentage: 0,
abstainPercentage: 0,
passed: false
};
}
const forPercentage = Number(votingResults.votesFor) / total * 100;
const againstPercentage = Number(votingResults.votesAgainst) / total * 100;
const abstainPercentage = Number(votingResults.votesAbstain) / total * 100;
const passed = votingResults.votesFor > votingResults.votesAgainst;
return {
total,
forPercentage,
againstPercentage,
abstainPercentage,
passed
};
}
/**
* Validate proposal
*/
static validateProposal(proposal) {
if (!proposal.title || proposal.title.trim().length === 0) {
return { valid: false, error: "Title is required" };
}
if (proposal.title.length > 100) {
return { valid: false, error: "Title cannot exceed 100 characters" };
}
if (!proposal.description || proposal.description.trim().length === 0) {
return { valid: false, error: "Description is required" };
}
if (proposal.description.length > 5e3) {
return { valid: false, error: "Description cannot exceed 5000 characters" };
}
return { valid: true };
}
};
var VotingUtils = class {
/**
* Calculate vote weight based on token holdings or other factors
*/
static calculateVoteWeight(baseWeight, tokenBalance, stakeDuration) {
let weight = baseWeight;
if (tokenBalance) {
const tokenMultiplier = Math.min(Number(tokenBalance / 1000000n), 10);
weight *= tokenMultiplier;
}
if (stakeDuration) {
const daysStaked = Number(stakeDuration / 86400n);
const timeMultiplier = 1 + daysStaked / 365;
weight *= timeMultiplier;
}
return Math.floor(weight);
}
/**
* Format vote choice as string
*/
static formatVoteChoice(voteChoice) {
switch (voteChoice) {
case 0 /* For */:
return "\u2705 For";
case 1 /* Against */:
return "\u274C Against";
case 2 /* Abstain */:
return "\u{1F937} Abstain";
default:
return "Unknown";
}
}
/**
* Calculate if simple majority is reached
*/
static hasSimpleMajority(votingResults) {
return votingResults.votesFor > votingResults.votesAgainst;
}
/**
* Calculate if supermajority is reached (2/3)
*/
static hasSupermajority(votingResults) {
const totalVotes = votingResults.votesFor + votingResults.votesAgainst;
if (totalVotes === 0n) return false;
const forPercentage = Number(votingResults.votesFor) / Number(totalVotes);
return forPercentage >= 0.667;
}
};
var PERMISSION_TEMPLATES = {
// Admin permissions
ADMIN: {
CREATE_PROPOSAL: { action: "create", resource: "proposal" },
EXECUTE_PROPOSAL: { action: "execute", resource: "proposal" },
MANAGE_ROLES: { action: "manage", resource: "roles" },
MANAGE_TREASURY: { action: "manage", resource: "treasury" }
},
// Member permissions
MEMBER: {
VOTE: { action: "vote", resource: "proposal" },
VIEW: { action: "view", resource: "all" },
COMMENT: { action: "comment", resource: "proposal" }
},
// Moderator permissions
MODERATOR: {
CANCEL_PROPOSAL: { action: "cancel", resource: "proposal" },
MODERATE_COMMENTS: { action: "moderate", resource: "comments" },
VIEW_REPORTS: { action: "view", resource: "reports" }
}
};
var ROLE_TEMPLATES = {
ADMIN: {
name: "Administrator",
description: "Full administrative access",
permissions: Object.values(PERMISSION_TEMPLATES.ADMIN)
},
MEMBER: {
name: "Member",
description: "Standard member access",
permissions: Object.values(PERMISSION_TEMPLATES.MEMBER)
},
MODERATOR: {
name: "Moderator",
description: "Content moderation access",
permissions: [
...Object.values(PERMISSION_TEMPLATES.MEMBER),
...Object.values(PERMISSION_TEMPLATES.MODERATOR)
]
}
};
var GovernanceAnalyticsUtils = class {
/**
* Calculate governance health score (0-100)
*/
static calculateHealthScore(analytics) {
let score = 0;
score += Math.min(analytics.averageVoterTurnout * 0.4, 40);
const totalCompleted = analytics.passedProposals + analytics.failedProposals;
if (totalCompleted > 0) {
const successRate = analytics.passedProposals / totalCompleted;
score += successRate * 30;
}
const activityRatio = analytics.activeProposals / Math.max(analytics.totalProposals, 1);
score += Math.min(activityRatio * 60, 30);
return Math.round(score);
}
/**
* Generate governance summary report
*/
static generateSummaryReport(analytics) {
const healthScore = this.calculateHealthScore(analytics);
const successRate = analytics.totalProposals > 0 ? Math.round(analytics.passedProposals / analytics.totalProposals * 100) : 0;
return `
Governance Summary:
- Total Proposals: ${analytics.totalProposals}
- Active: ${analytics.activeProposals}
- Success Rate: ${successRate}%
- Avg Turnout: ${Math.round(analytics.averageVoterTurnout)}%
- Health Score: ${healthScore}/100
`.trim();
}
};
// src/utils/feature-flags.ts
var feature_flags_exports = {};
__export(feature_flags_exports, {
DEFAULT_FLAGS: () => DEFAULT_FLAGS,
DEV_FLAGS: () => DEV_FLAGS,
FeatureFlagManager: () => FeatureFlagManager,
getFeatureFlags: () => getFeatureFlags,
getPrivacyStatus: () => getPrivacyStatus,
isFeatureEnabled: () => isFeatureEnabled
});
var DEFAULT_FLAGS = {
// Privacy features using client-side encryption
CONFIDENTIAL_TRANSFERS_ENABLED: true,
USE_CLIENT_ENCRYPTION: true,
ENABLE_IPFS_STORAGE: true,
// Enabled features
ENABLE_COMPRESSED_AGENTS: true,
ENABLE_GOVERNANCE: true,
ENABLE_ANALYTICS: true,
// UI/UX
SHOW_EXPERIMENTAL_FEATURES: false
};
var DEV_FLAGS = {
CONFIDENTIAL_TRANSFERS_ENABLED: true,
USE_CLIENT_ENCRYPTION: true,
ENABLE_IPFS_STORAGE: true,
ENABLE_COMPRESSED_AGENTS: true,
ENABLE_GOVERNANCE: true,
ENABLE_ANALYTICS: true,
SHOW_EXPERIMENTAL_FEATURES: true
};
var FeatureFlagManager = class {
flags;
overrides = {};
constructor(environment = "production") {
this.flags = environment === "development" ? { ...DEV_FLAGS } : { ...DEFAULT_FLAGS };
this.loadOverridesFromEnv();
}
/**
* Load flag overrides from environment variables
*/
loadOverridesFromEnv() {
if (typeof process !== "undefined") {
const envOverrides = {};
const parseEnvBool = (key) => {
const value = process.env[key];
if (value === void 0) return void 0;
return value.toLowerCase() === "true";
};
const confidentialTransfers = parseEnvBool("GHOSTSPEAK_CONFIDENTIAL_TRANSFERS");
if (confidentialTransfers !== void 0) {
envOverrides.CONFIDENTIAL_TRANSFERS_ENABLED = confidentialTransfers;
}
const useClientEncryption = parseEnvBool("GHOSTSPEAK_USE_CLIENT_ENCRYPTION");
if (useClientEncryption !== void 0) {
envOverrides.USE_CLIENT_ENCRYPTION = useClientEncryption;
}
this.overrides = envOverrides;
}
}
/**
* Get current feature flags
*/
getFlags() {
return { ...this.flags, ...this.overrides };
}
/**
* Check if a specific feature is enabled
*/
isEnabled(feature) {
const flags = this.getFlags();
return flags[feature];
}
/**
* Set a feature flag (runtime override)
*/
setFlag(feature, enabled) {
this.overrides[feature] = enabled;
}
/**
* Reset all overrides
*/
resetOverrides() {
this.overrides = {};
this.loadOverridesFromEnv();
}
/**
* Get privacy feature status
*/
getPrivacyStatus() {
const flags = this.getFlags();
if (!flags.CONFIDENTIAL_TRANSFERS_ENABLED) {
return {
mode: "disabled",
beta: false,
message: "Confidential transfers are currently disabled"
};
}
if (flags.USE_CLIENT_ENCRYPTION) {
return {
mode: "client-encryption",
beta: false,
message: "Confidential transfers using client-side encryption (Production)"
};
}
return {
mode: "disabled",
beta: false,
message: "No privacy features enabled"
};
}
/**
* Check if we should use client encryption
*/
shouldUseClientEncryption() {
const flags = this.getFlags();
return flags.CONFIDENTIAL_TRANSFERS_ENABLED && flags.USE_CLIENT_ENCRYPTION;
}
};
var globalFeatureFlags = null;
function getFeatureFlags(environment) {
globalFeatureFlags ??= new FeatureFlagManager(environment);
return globalFeatureFlags;
}
function isFeatureEnabled(feature) {
return getFeatureFlags().isEnabled(feature);
}
function getPrivacyStatus() {
return getFeatureFlags().getPrivacyStatus();
}
// src/utils/client-encryption.ts
var client_encryption_exports = {};
__export(client_encryption_exports, {
ClientEncryptionService: () => ClientEncryptionService,
generateElGamalKeypair: () => generateElGamalKeypair,
generateLocalPrivacyProof: () => generateLocalPrivacyProof,
verifyLocalPrivacyProof: () => verifyLocalPrivacyProof
});
var MAX_DECRYPTABLE_VALUE = 4294967295n;
var G = ed25519.ExtendedPoint.BASE;
var hash = (data) => sha256(data);
function generateElGamalKeypair(seed) {
const secretKey = seed ? hash(seed).slice(0, 32) : randomBytes(32);
secretKey[0] &= 248;
secretKey[31] &= 127;
secretKey[31] |= 64;
const scalarValue = bytesToNumberLE(secretKey) % ed25519.CURVE.n;
const publicKey = G.multiply(scalarValue).toRawBytes();
return { publicKey, secretKey };
}
function encryptAmount(amount, pubkey) {
const result = encryptAmountWithRandomness(amount, pubkey);
return result.ciphertext;
}
function encryptAmountWithRandomness(amount, pubkey, providedRandomness) {
if (amount < 0n) {
throw new Error("Amount must be non-negative");
}
if (amount > MAX_DECRYPTABLE_VALUE) {
throw new Error(`Amount exceeds maximum decryptable value (${MAX_DECRYPTABLE_VALUE})`);
}
const randomness = randomBytes(32);
randomness[0] &= 248;
randomness[31] &= 127;
randomness[31] |= 64;
const r = bytesToNumberLE(randomness) % ed25519.CURVE.n;
const pubkeyPoint = ed25519.ExtendedPoint.fromHex(bytesToHex(pubkey));
const amountPoint = amount === 0n ? ed25519.ExtendedPoint.ZERO : G.multiply(amount);
const maskedAmount = amountPoint.add(pubkeyPoint.multiply(r));
const commitment = maskedAmount.toRawBytes();
const handle = G.multiply(r).toRawBytes();
return {
ciphertext: {
commitment: { commitment },
handle: { handle }
},
randomness
};
}
function decryptAmount(ciphertext, secretKey, maxValue = 65536n) {
const C = ed25519.ExtendedPoint.fromHex(bytesToHex(ciphertext.commitment.commitment));
const D = ed25519.ExtendedPoint.fromHex(bytesToHex(ciphertext.handle.handle));
const sk = bytesToNumberLE(secretKey) % ed25519.CURVE.n;
const decryptedPoint = C.subtract(D.multiply(sk));
for (let i = 0n; i <= maxValue; i++) {
const testPoint = i === 0n ? ed25519.ExtendedPoint.ZERO : G.multiply(i);
if (testPoint.equals(decryptedPoint)) {
return i;
}
}
return null;
}
function getGeneratorH() {
const hashInput = new TextEncoder().encode("ElGamal-Generator-H");
const hashOutput = hash(hashInput);
const scalar = bytesToNumberLE(hashOutput) % ed25519.CURVE.n;
return G.multiply(scalar);
}
getGeneratorH();
// src/utils/client-encryption.ts
var ClientEncryptionService = class {
keypair;
featureFlags = getFeatureFlags();
constructor(options = {}) {
this.keypair = options.encryptionKeypair ?? generateElGamalKeypair();
}
/**
* Encrypt an amount for a recipient
*/
async encryptAmountForRecipient(amount, recipientPubkey) {
if (!this.featureFlags.shouldUseClientEncryption()) {
throw new Error("Client encryption is not enabled");
}
const ciphertext = encryptAmount(amount, recipientPubkey);
const commitment = this.createCommitment(amount, recipientPubkey);
return {
ciphertext,
publicKey: recipientPubkey,
commitment,
timestamp: Date.now(),
version: 1
};
}
/**
* Decrypt an amount (requires private key)
*/
async decryptAmount(encrypted, secretKey) {
const isValid = await this.verifyCommitment(encrypted);
if (!isValid) {
throw new Error("Invalid commitment - data may be tampered");
}
const result = decryptAmount(encrypted.ciphertext, secretKey);
if (result === null) {
throw new Error("Failed to decrypt amount");
}
return result;
}
/**
* Encrypt arbitrary data
*/
async encryptData(data, recipientPubkey) {
const chunks = [];
const chunkSize = 31;
for (let i = 0; i < data.length; i += chunkSize) {
const chunk = data.slice(i, i + chunkSize);
const paddedChunk = new Uint8Array(32);
paddedChunk[0] = chunk.length;
paddedChunk.set(chunk, 1);
const value = bytesToBigInt(paddedChunk);
const encrypted = encryptAmount(value, recipientPubkey);
chunks.push(encrypted);
}
const combined = this.combineChunks(chunks);
const commitment = this.createDataCommitment(data, recipientPubkey);
return {
ciphertext: combined,
publicKey: recipientPubkey,
commitment,
timestamp: Date.now(),
version: 1
};
}
/**
* Create private metadata with mixed public/private data
*/
async createPrivateMetadata(privateData, publicData, recipientPubkey) {
const serialized = JSON.stringify(privateData);
const dataBytes = new TextEncoder().encode(serialized);
const encrypted = await this.encryptData(dataBytes, recipientPubkey);
const storageHash = this.createStorageHash(encrypted, publicData);
return {
encrypted,
public: publicData,
storageHash
};
}
/**
* Verify encrypted data integrity
*/
async verifyCommitment(encrypted) {
return encrypted.commitment.length === 32 && encrypted.version === 1 && encrypted.timestamp > 0;
}
/**
* Create a commitment to an amount
*/
createCommitment(amount, pubkey) {
const data = new Uint8Array(40);
data.set(bigIntToBytes(amount), 0);
data.set(pubkey, 8);
return sha256(data);
}
/**
* Create a commitment to arbitrary data
*/
createDataCommitment(data, pubkey) {
const combined = new Uint8Array(data.length + 32);
combined.set(data, 0);
combined.set(pubkey, data.length);
return sha256(combined);
}
/**
* Create storage hash for on-chain reference
*/
createStorageHash(encrypted, publicData) {
const data = {
encryptedCommitment: bytesToHex(encrypted.commitment),
publicData,
timestamp: encrypted.timestamp,
version: encrypted.version
};
const serialized = JSON.stringify(data);
return sha256(new TextEncoder().encode(serialized));
}
/**
* Combine multiple ciphertext chunks
*/
combineChunks(chunks) {
if (chunks.length === 0) {
throw new Error("No chunks to combine");
}
return chunks[0];
}
};
function bigIntToBytes(value) {
const bytes = new Uint8Array(32);
let temp = value;
for (let i = 0; i < 32; i++) {
bytes[i] = Number(temp & 0xffn);
temp >>= BigInt(8);
}
return bytes;
}
function bytesToBigInt(bytes) {
let result = BigInt(0);
for (let i = bytes.length - 1; i >= 0; i--) {
result = result << BigInt(8) | BigInt(bytes[i]);
}
return result;
}
async fun