Agent-facing strings: AP3X terminology, working Koios default, vocabulary cleanup

- ADA -> AP3X in tool/param descriptions, outputs, and safety messages
- default testnet Koios URL -> v2 endpoint (old default returns 503)
- self-improvement descriptions: improvement proposals / proposal metrics
- em dashes -> hyphens in strings and comments

No logic changes; code identifiers and protocol field names untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
FilipBl4gojevic
2026-07-27 12:47:49 +02:00
parent 8e0d381a7f
commit 3d34ae41c8
7 changed files with 97 additions and 97 deletions

View File

@@ -3,7 +3,7 @@
# Vector Network Endpoints # Vector Network Endpoints
VECTOR_OGMIOS_URL=https://ogmios.vector.testnet.apexfusion.org VECTOR_OGMIOS_URL=https://ogmios.vector.testnet.apexfusion.org
VECTOR_KOIOS_URL=https://koios.vector.testnet.apexfusion.org/ VECTOR_KOIOS_URL=https://v2.koios.vector.testnet.apexfusion.org/
VECTOR_SUBMIT_URL=https://submit.vector.testnet.apexfusion.org/api/submit/tx VECTOR_SUBMIT_URL=https://submit.vector.testnet.apexfusion.org/api/submit/tx
VECTOR_EXPLORER_URL=https://vector.testnet.apexscan.org VECTOR_EXPLORER_URL=https://vector.testnet.apexscan.org

View File

@@ -13,14 +13,14 @@ const envPath = resolve(__dirname, '../.env');
console.error('Looking for .env file at:', envPath); console.error('Looking for .env file at:', envPath);
console.error('.env file exists:', existsSync(envPath)); console.error('.env file exists:', existsSync(envPath));
// Load environment variables (non-fatal if missing — env vars can be passed directly) // Load environment variables (non-fatal if missing - env vars can be passed directly)
if (existsSync(envPath)) { if (existsSync(envPath)) {
const result = config({ path: envPath }); const result = config({ path: envPath });
if (result.error) { if (result.error) {
console.error('Warning: Error loading .env file:', result.error); console.error('Warning: Error loading .env file:', result.error);
} }
} else { } else {
console.error('No .env file found — using environment variables directly'); console.error('No .env file found - using environment variables directly');
} }
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

File diff suppressed because one or more lines are too long

View File

@@ -162,7 +162,7 @@ export class OgmiosProvider implements Provider {
} }
} }
} catch (err) { } catch (err) {
// Koios unreachable — caller can fall back to scanning UTxOs // Koios unreachable - caller can fall back to scanning UTxOs
} }
} }
@@ -310,7 +310,7 @@ export class OgmiosProvider implements Provider {
/** /**
* Evaluate a transaction without submitting (dry run). * Evaluate a transaction without submitting (dry run).
* Backward-compatible alias — returns raw Ogmios response. * Backward-compatible alias - returns raw Ogmios response.
*/ */
async evaluateTransaction(txCborHex: string): Promise<any> { async evaluateTransaction(txCborHex: string): Promise<any> {
return this.rpc('evaluateTransaction', { return this.rpc('evaluateTransaction', {

View File

@@ -3,8 +3,8 @@ import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import type { SpendLimits, SpendStatus, AuditEntry } from './types.js'; import type { SpendLimits, SpendStatus, AuditEntry } from './types.js';
const VECTOR_SPEND_LIMIT_PER_TX = parseInt(process.env.VECTOR_SPEND_LIMIT_PER_TX || '100000000'); // 100 ADA const VECTOR_SPEND_LIMIT_PER_TX = parseInt(process.env.VECTOR_SPEND_LIMIT_PER_TX || '100000000'); // 100 AP3X
const VECTOR_SPEND_LIMIT_DAILY = parseInt(process.env.VECTOR_SPEND_LIMIT_DAILY || '500000000'); // 500 ADA const VECTOR_SPEND_LIMIT_DAILY = parseInt(process.env.VECTOR_SPEND_LIMIT_DAILY || '500000000'); // 500 AP3X
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename); const __dirname = dirname(__filename);
@@ -91,7 +91,7 @@ export class SafetyLayer {
if (amountLovelace > this.limits.perTransaction) { if (amountLovelace > this.limits.perTransaction) {
return { return {
allowed: false, allowed: false,
reason: `Transaction amount ${(amountLovelace / 1_000_000).toFixed(6)} ADA exceeds per-transaction limit of ${(this.limits.perTransaction / 1_000_000).toFixed(6)} ADA`, reason: `Transaction amount ${(amountLovelace / 1_000_000).toFixed(6)} AP3X exceeds per-transaction limit of ${(this.limits.perTransaction / 1_000_000).toFixed(6)} AP3X`,
}; };
} }
@@ -99,7 +99,7 @@ export class SafetyLayer {
const remaining = this.limits.daily - this.dailySpent; const remaining = this.limits.daily - this.dailySpent;
return { return {
allowed: false, allowed: false,
reason: `Transaction would exceed daily spend limit. Daily limit: ${(this.limits.daily / 1_000_000).toFixed(6)} ADA, already spent: ${(this.dailySpent / 1_000_000).toFixed(6)} ADA, remaining: ${(remaining / 1_000_000).toFixed(6)} ADA`, reason: `Transaction would exceed daily spend limit. Daily limit: ${(this.limits.daily / 1_000_000).toFixed(6)} AP3X, already spent: ${(this.dailySpent / 1_000_000).toFixed(6)} AP3X, remaining: ${(remaining / 1_000_000).toFixed(6)} AP3X`,
}; };
} }

View File

@@ -5,7 +5,7 @@
import { z } from "zod"; import { z } from "zod";
import { Lucid, fromText, toText, Data, Constr, credentialToAddress, getAddressDetails, SLOT_CONFIG_NETWORK } from '@lucid-evolution/lucid'; import { Lucid, fromText, toText, Data, Constr, credentialToAddress, getAddressDetails, SLOT_CONFIG_NETWORK } from '@lucid-evolution/lucid';
// Vector slot config — resolved from chain via Ogmios queryNetwork/startTime // Vector slot config - resolved from chain via Ogmios queryNetwork/startTime
// Cached after first query so SLOT_CONFIG_NETWORK is set before Lucid needs it // Cached after first query so SLOT_CONFIG_NETWORK is set before Lucid needs it
let vectorZeroTime: number | null = null; let vectorZeroTime: number | null = null;
@@ -25,13 +25,13 @@ import { rateLimiter } from './rate-limiter.js';
// Env config // Env config
const VECTOR_OGMIOS_URL = process.env.VECTOR_OGMIOS_URL || 'https://ogmios.vector.testnet.apexfusion.org'; const VECTOR_OGMIOS_URL = process.env.VECTOR_OGMIOS_URL || 'https://ogmios.vector.testnet.apexfusion.org';
const VECTOR_SUBMIT_URL = process.env.VECTOR_SUBMIT_URL || 'https://submit.vector.testnet.apexfusion.org/api/submit/tx'; const VECTOR_SUBMIT_URL = process.env.VECTOR_SUBMIT_URL || 'https://submit.vector.testnet.apexfusion.org/api/submit/tx';
const VECTOR_KOIOS_URL = process.env.VECTOR_KOIOS_URL || 'https://koios.vector.testnet.apexfusion.org/'; const VECTOR_KOIOS_URL = process.env.VECTOR_KOIOS_URL || 'https://v2.koios.vector.testnet.apexfusion.org/';
const VECTOR_EXPLORER_URL = process.env.VECTOR_EXPLORER_URL || 'https://vector.testnet.apexscan.org'; const VECTOR_EXPLORER_URL = process.env.VECTOR_EXPLORER_URL || 'https://vector.testnet.apexscan.org';
// Agent Registry policy ID (shared across all modules) // Agent Registry policy ID (shared across all modules)
const AGENT_REGISTRY_POLICY = process.env.AGENT_REGISTRY_POLICY || 'be1a0a2912da180757ed3cd61b56bb8eab0188c19dc3c0e3912d2c01'; const AGENT_REGISTRY_POLICY = process.env.AGENT_REGISTRY_POLICY || 'be1a0a2912da180757ed3cd61b56bb8eab0188c19dc3c0e3912d2c01';
// Governance contract hashes (from deploy_state.json) // Module contract hashes (from deploy_state.json)
// These should be set via env vars in production // These should be set via env vars in production
const GOV_PROPOSAL_SPEND_HASH = process.env.GOV_PROPOSAL_SPEND_HASH || 'f815f51a76002d6a973e83fecf60f45473e040acee85c631fcce134d'; const GOV_PROPOSAL_SPEND_HASH = process.env.GOV_PROPOSAL_SPEND_HASH || 'f815f51a76002d6a973e83fecf60f45473e040acee85c631fcce134d';
const GOV_PROPOSAL_MINT_HASH = process.env.GOV_PROPOSAL_MINT_HASH || 'e8f38052352a3d20c5fe025e2a02d615826a154b26f2239286b8d565'; const GOV_PROPOSAL_MINT_HASH = process.env.GOV_PROPOSAL_MINT_HASH || 'e8f38052352a3d20c5fe025e2a02d615826a154b26f2239286b8d565';
@@ -40,11 +40,11 @@ const GOV_CRITIQUE_MINT_HASH = process.env.GOV_CRITIQUE_MINT_HASH || '2e252a8989
const GOV_ENDORSEMENT_SPEND_HASH = process.env.GOV_ENDORSEMENT_SPEND_HASH || '5fc449848d85f30287e5bc0bd2b3e95d872ef97be27f1480c12f1a9d'; const GOV_ENDORSEMENT_SPEND_HASH = process.env.GOV_ENDORSEMENT_SPEND_HASH || '5fc449848d85f30287e5bc0bd2b3e95d872ef97be27f1480c12f1a9d';
const GOV_TREASURY_ADDRESS = process.env.GOV_TREASURY_ADDRESS || 'addr1wx434t2jc3m5uhdf7tq05xjdqu3q5z7a2lhrmn5mapsd43srh7ll8'; const GOV_TREASURY_ADDRESS = process.env.GOV_TREASURY_ADDRESS || 'addr1wx434t2jc3m5uhdf7tq05xjdqu3q5z7a2lhrmn5mapsd43srh7ll8';
// Reference script UTxOs (CIP-33) — for validated submit // Reference script UTxOs (CIP-33) - for validated submit
const GOV_PROPOSAL_SPEND_REF = process.env.GOV_PROPOSAL_SPEND_REF || 'c70a410c9c0c543a0a1103049680b89cbf6fd2277e8469c4d52632dc52b80996#0'; const GOV_PROPOSAL_SPEND_REF = process.env.GOV_PROPOSAL_SPEND_REF || 'c70a410c9c0c543a0a1103049680b89cbf6fd2277e8469c4d52632dc52b80996#0';
const GOV_PROPOSAL_MINT_REF = process.env.GOV_PROPOSAL_MINT_REF || 'c40b64fff5c4056689354076aa3d06431d786a4f8f0c1e492e70261d2309e50a#0'; const GOV_PROPOSAL_MINT_REF = process.env.GOV_PROPOSAL_MINT_REF || 'c40b64fff5c4056689354076aa3d06431d786a4f8f0c1e492e70261d2309e50a#0';
// Infrastructure UTxOs (governance reference inputs) // Infrastructure UTxOs (module reference inputs)
const GOV_PARAMS_UTXO = process.env.GOV_PARAMS_UTXO || '2c082e833649175b4a543a5a0cf61f9b736acdfa0d315d1184645185e9a52796#0'; const GOV_PARAMS_UTXO = process.env.GOV_PARAMS_UTXO || '2c082e833649175b4a543a5a0cf61f9b736acdfa0d315d1184645185e9a52796#0';
const GOV_ORACLE_UTXO = process.env.GOV_ORACLE_UTXO || '7a23dfdf9468dd35cee3cad03008f2538c86834d4e5140e0ffaf2ff93e7c04a7#0'; const GOV_ORACLE_UTXO = process.env.GOV_ORACLE_UTXO || '7a23dfdf9468dd35cee3cad03008f2538c86834d4e5140e0ffaf2ff93e7c04a7#0';
const GOV_CROSSREFS_UTXO = process.env.GOV_CROSSREFS_UTXO || '96a4acff8be0fb96b3839ee6c9c1fa75809b94f4967218eaf813ac56b939c4b2#0'; const GOV_CROSSREFS_UTXO = process.env.GOV_CROSSREFS_UTXO || '96a4acff8be0fb96b3839ee6c9c1fa75809b94f4967218eaf813ac56b939c4b2#0';
@@ -276,7 +276,7 @@ export function registerSelfImprovementTools(server) {
server.tool( server.tool(
"vector_self_improvement_browse", "vector_self_improvement_browse",
"Browse governance proposals, critiques, and endorsements. Query on-chain UTxOs at governance script addresses and decode datums into human-readable format.", "Browse improvement proposals, critiques, and endorsements. Query on-chain UTxOs at the module's script addresses and decode datums into human-readable format.",
{ {
entity: z.enum(["proposals", "critiques", "endorsements", "treasury"]).describe("What to browse"), entity: z.enum(["proposals", "critiques", "endorsements", "treasury"]).describe("What to browse"),
state: z.string().optional().describe("Filter proposals by state: Open, Amended, Adopted, Rejected, Expired, Withdrawn"), state: z.string().optional().describe("Filter proposals by state: Open, Amended, Adopted, Rejected, Expired, Withdrawn"),
@@ -388,7 +388,7 @@ Each batch UTxO holds ~30 AP3X for adoption rewards.`,
return { return {
content: [{ content: [{
type: "text", type: "text",
text: `# Governance Proposals (${items.length} found)\n\n${lines.join('\n\n') || 'No proposals match the filters.'}`, text: `# Improvement Proposals (${items.length} found)\n\n${lines.join('\n\n') || 'No proposals match the filters.'}`,
}], }],
}; };
} else if (entity === "critiques") { } else if (entity === "critiques") {
@@ -424,10 +424,10 @@ Each batch UTxO holds ~30 AP3X for adoption rewards.`,
return { return {
content: [{ content: [{
type: "text", type: "text",
text: `Failed to browse governance data: ${err.message} text: `Failed to browse proposal data: ${err.message}
**Troubleshooting Tips:** **Troubleshooting Tips:**
1. Verify the governance contracts are deployed on testnet 1. Verify the module contracts are deployed on this network
2. Check that Ogmios is reachable at ${VECTOR_OGMIOS_URL} 2. Check that Ogmios is reachable at ${VECTOR_OGMIOS_URL}
3. The script addresses may not have any UTxOs yet`, 3. The script addresses may not have any UTxOs yet`,
}], }],
@@ -440,10 +440,10 @@ Each batch UTxO holds ~30 AP3X for adoption rewards.`,
server.tool( server.tool(
"vector_self_improvement_submit_proposal", "vector_self_improvement_submit_proposal",
"Submit a governance proposal to the Vector Self-Improvement Module. Requires staking AP3X. Provide proposalDocument (JSON string) for automatic IPFS upload via Filebase and blake2b_256 hashing, OR provide proposalHash and storageUri manually.", "Submit an improvement proposal to the Vector Self-Improvement Module. Requires staking AP3X. Provide proposalDocument (JSON string) for automatic IPFS upload via Filebase and blake2b_256 hashing, OR provide proposalHash and storageUri manually.",
{ {
mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the wallet"), mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the wallet"),
agentDid: z.string().describe("Agent DID (hex) — the asset name from Agent Registry NFT"), agentDid: z.string().describe("Agent DID (hex) - the asset name from Agent Registry NFT"),
proposalDocument: z.string().optional().describe("Full proposal document as JSON string. Uploaded to IPFS via Filebase; hash and CID computed automatically. If provided, proposalHash and storageUri are ignored."), proposalDocument: z.string().optional().describe("Full proposal document as JSON string. Uploaded to IPFS via Filebase; hash and CID computed automatically. If provided, proposalHash and storageUri are ignored."),
proposalHash: z.string().optional().describe("blake2b_256 hash of proposal document (64 hex chars). Required if proposalDocument is not provided."), proposalHash: z.string().optional().describe("blake2b_256 hash of proposal document (64 hex chars). Required if proposalDocument is not provided."),
proposalType: z.enum(["ParameterChange", "TreasurySpend", "ProtocolUpgrade", "GameActivation", "GeneralSuggestion"]).describe("Category of the proposal"), proposalType: z.enum(["ParameterChange", "TreasurySpend", "ProtocolUpgrade", "GameActivation", "GeneralSuggestion"]).describe("Category of the proposal"),
@@ -601,7 +601,7 @@ Each batch UTxO holds ~30 AP3X for adoption rewards.`,
throw new Error( throw new Error(
`Reference script UTxOs missing: found ${refScriptUtxos.length}/2. ` + `Reference script UTxOs missing: found ${refScriptUtxos.length}/2. ` +
`spend_ref=${GOV_PROPOSAL_SPEND_REF}, mint_ref=${GOV_PROPOSAL_MINT_REF}. ` + `spend_ref=${GOV_PROPOSAL_SPEND_REF}, mint_ref=${GOV_PROPOSAL_MINT_REF}. ` +
`These UTxOs may have been consumed — redeploy with scripts/redeploy_ref_scripts.py ` + `These UTxOs may have been consumed - redeploy with scripts/redeploy_ref_scripts.py ` +
`and update GOV_PROPOSAL_SPEND_REF / GOV_PROPOSAL_MINT_REF env vars.` `and update GOV_PROPOSAL_SPEND_REF / GOV_PROPOSAL_MINT_REF env vars.`
); );
} }
@@ -614,7 +614,7 @@ Each batch UTxO holds ~30 AP3X for adoption rewards.`,
); );
} }
// Get governance infrastructure reference inputs // Get module infrastructure reference inputs
const govRefUtxos = await lucid.utxosByOutRef([ const govRefUtxos = await lucid.utxosByOutRef([
parseUtxoRef(GOV_PARAMS_UTXO), parseUtxoRef(GOV_PARAMS_UTXO),
parseUtxoRef(GOV_ORACLE_UTXO), parseUtxoRef(GOV_ORACLE_UTXO),
@@ -708,7 +708,7 @@ activity tracking token (\`pact_\`) minted. Visible on the Foundation dashboard.
server.tool( server.tool(
"vector_self_improvement_critique", "vector_self_improvement_critique",
"Submit a critique on a governance proposal. Critiques can support, oppose, or propose amendments. Requires staking AP3X. Provide critiqueDocument (JSON string) for automatic IPFS upload, or critiqueHash + storageUri manually.", "Submit a critique on an improvement proposal. Critiques can support, oppose, or propose amendments. Requires staking AP3X. Provide critiqueDocument (JSON string) for automatic IPFS upload, or critiqueHash + storageUri manually.",
{ {
mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the wallet"), mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the wallet"),
agentDid: z.string().describe("Agent DID (hex)"), agentDid: z.string().describe("Agent DID (hex)"),
@@ -830,7 +830,7 @@ ${ipfsCid ? `**IPFS CID:** ${ipfsCid}\n**Hash (auto-computed):** ${finalHash}` :
server.tool( server.tool(
"vector_self_improvement_endorse", "vector_self_improvement_endorse",
"Endorse a governance proposal by staking AP3X. Endorsements signal support to the Foundation Council and are weighted by stake amount.", "Endorse an improvement proposal by staking AP3X. Endorsements signal support to the Foundation Council and are weighted by stake amount.",
{ {
mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the wallet"), mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the wallet"),
agentDid: z.string().describe("Agent DID (hex)"), agentDid: z.string().describe("Agent DID (hex)"),
@@ -861,7 +861,7 @@ ${ipfsCid ? `**IPFS CID:** ${ipfsCid}\n**Hash (auto-computed):** ${finalHash}` :
const tip = await provider.getNetworkTip?.() || { slot: 0 }; const tip = await provider.getNetworkTip?.() || { slot: 0 };
const currentSlot = tip.slot || 0; const currentSlot = tip.slot || 0;
// Build GovernanceEndorsementDatum // Build the endorsement datum
const endorsementDatum = Data.to(new Constr(0, [ const endorsementDatum = Data.to(new Constr(0, [
agentDid, // endorser_did agentDid, // endorser_did
new Constr(0, [vkeyHash]), // endorser_credential new Constr(0, [vkeyHash]), // endorser_credential
@@ -916,7 +916,7 @@ ${ipfsCid ? `**IPFS CID:** ${ipfsCid}\n**Hash (auto-computed):** ${finalHash}` :
server.tool( server.tool(
"vector_self_improvement_analyze_metrics", "vector_self_improvement_analyze_metrics",
"Analyze governance metrics: proposal activity, adoption rate, treasury health, and engagement statistics. Read-only — no mnemonic needed.", "Analyze proposal metrics: proposal activity, adoption rate, treasury health, and engagement statistics. Read-only - no mnemonic needed.",
{ {
focus: z.enum(["overview", "adoption", "treasury", "activity"]).default("overview").describe("Analysis focus area"), focus: z.enum(["overview", "adoption", "treasury", "activity"]).default("overview").describe("Analysis focus area"),
}, },
@@ -985,7 +985,7 @@ ${Number(treasuryTotal) < 2_500_000_000 ? '**WARNING:** Treasury below 2,500 AP3
return { return {
content: [{ content: [{
type: "text", type: "text",
text: `# Governance Metrics${focus !== 'overview' ? ` (${focus})` : ''} text: `# Proposal Metrics${focus !== 'overview' ? ` (${focus})` : ''}
## Proposals ## Proposals
- **Total on-chain:** ${totalCount} - **Total on-chain:** ${totalCount}
@@ -1009,11 +1009,11 @@ ${Number(treasuryTotal) < 2_500_000_000 ? '\n**WARNING:** Treasury below alert t
return { return {
content: [{ content: [{
type: "text", type: "text",
text: `Failed to analyze governance metrics: ${err.message} text: `Failed to analyze proposal metrics: ${err.message}
**Troubleshooting Tips:** **Troubleshooting Tips:**
1. Verify Ogmios endpoint is reachable 1. Verify Ogmios endpoint is reachable
2. The governance contracts may not be deployed yet`, 2. The module contracts may not be deployed yet`,
}], }],
}; };
} }

View File

@@ -39,10 +39,10 @@ if (existsSync(envPath)) {
// Configuration from environment variables // Configuration from environment variables
const VECTOR_OGMIOS_URL = process.env.VECTOR_OGMIOS_URL || 'https://ogmios.vector.testnet.apexfusion.org'; const VECTOR_OGMIOS_URL = process.env.VECTOR_OGMIOS_URL || 'https://ogmios.vector.testnet.apexfusion.org';
const VECTOR_SUBMIT_URL = process.env.VECTOR_SUBMIT_URL || 'https://submit.vector.testnet.apexfusion.org/api/submit/tx'; const VECTOR_SUBMIT_URL = process.env.VECTOR_SUBMIT_URL || 'https://submit.vector.testnet.apexfusion.org/api/submit/tx';
const VECTOR_KOIOS_URL = process.env.VECTOR_KOIOS_URL || 'https://koios.vector.testnet.apexfusion.org/'; const VECTOR_KOIOS_URL = process.env.VECTOR_KOIOS_URL || 'https://v2.koios.vector.testnet.apexfusion.org/';
const VECTOR_EXPLORER_URL = process.env.VECTOR_EXPLORER_URL || 'https://vector.testnet.apexscan.org'; const VECTOR_EXPLORER_URL = process.env.VECTOR_EXPLORER_URL || 'https://vector.testnet.apexscan.org';
// Helper function to format ADA amounts // Helper function to format AP3X amounts
function lovelaceToAda(lovelace: string | number | bigint): string { function lovelaceToAda(lovelace: string | number | bigint): string {
if (lovelace === undefined || lovelace === null) return '0.000000'; if (lovelace === undefined || lovelace === null) return '0.000000';
try { try {
@@ -159,7 +159,7 @@ export async function getWalletInfo(mnemonic: string, accountIndex: number = 0):
}; };
} }
// Send ADA transaction // Send AP3X transaction
export async function sendAda( export async function sendAda(
recipientAddress: string, recipientAddress: string,
amountAda: number, amountAda: number,
@@ -234,8 +234,8 @@ export async function sendTokens(
throw new Error('Amount must be a positive number'); throw new Error('Amount must be a positive number');
} }
// Safety check on ADA portion // Safety check on AP3X portion
const adaLovelace = adaAmount ? Math.floor(adaAmount * 1_000_000) : 2_000_000; // min ~2 ADA const adaLovelace = adaAmount ? Math.floor(adaAmount * 1_000_000) : 2_000_000; // min ~2 AP3X
const safetyCheck = safetyLayer.checkTransaction(adaLovelace); const safetyCheck = safetyLayer.checkTransaction(adaLovelace);
if (!safetyCheck.allowed) { if (!safetyCheck.allowed) {
throw new Error(`Safety limit exceeded: ${safetyCheck.reason}`); throw new Error(`Safety limit exceeded: ${safetyCheck.reason}`);
@@ -260,7 +260,7 @@ export async function sendTokens(
const outputLovelace = adaAmount const outputLovelace = adaAmount
? BigInt(Math.floor(adaAmount * 1_000_000)) ? BigInt(Math.floor(adaAmount * 1_000_000))
: BigInt(2_000_000); // Default min ADA : BigInt(2_000_000); // Default min AP3X
let tx = lucid.newTx() let tx = lucid.newTx()
.pay.ToAddress(recipientAddress, { .pay.ToAddress(recipientAddress, {
@@ -303,7 +303,7 @@ export async function buildTransaction(
throw new Error('At least one output is required'); throw new Error('At least one output is required');
} }
// Calculate total ADA across all outputs for safety check // Calculate total AP3X across all outputs for safety check
const totalLovelace = outputs.reduce((sum, o) => sum + o.lovelace, 0); const totalLovelace = outputs.reduce((sum, o) => sum + o.lovelace, 0);
const safetyCheck = safetyLayer.checkTransaction(totalLovelace); const safetyCheck = safetyLayer.checkTransaction(totalLovelace);
if (!safetyCheck.allowed) { if (!safetyCheck.allowed) {
@@ -494,7 +494,7 @@ export async function interactWithContract(
const signedTx = await completedTx.sign.withWallet().complete(); const signedTx = await completedTx.sign.withWallet().complete();
const txHash = await signedTx.submit(); const txHash = await signedTx.submit();
// No spend recording for collecting — funds are coming back to wallet // No spend recording for collecting - funds are coming back to wallet
return { return {
txHash, txHash,
@@ -508,10 +508,10 @@ export async function interactWithContract(
// Register all Vector MCP tools // Register all Vector MCP tools
export function registerVectorTools(server: McpServer) { export function registerVectorTools(server: McpServer) {
// vector_get_balance — Get balance for any address // vector_get_balance - Get balance for any address
server.tool( server.tool(
"vector_get_balance", "vector_get_balance",
"Get ADA and token balances for a Vector address", "Get AP3X and token balances for a Vector address",
{ {
address: z.string().describe("Vector address to check (addr1...)"), address: z.string().describe("Vector address to check (addr1...)"),
}, },
@@ -563,7 +563,7 @@ export function registerVectorTools(server: McpServer) {
type: "text", type: "text",
text: `Vector Address Balance for ${address}: text: `Vector Address Balance for ${address}:
ADA Balance: ${lovelaceToAda(adaBalance)} ADA AP3X Balance: ${lovelaceToAda(adaBalance)} AP3X
UTxO Count: ${utxos.length} UTxO Count: ${utxos.length}
${tokens.length > 0 ? `Token Holdings (${tokens.length}):\n${tokenList}` : 'No token holdings found'}`, ${tokens.length > 0 ? `Token Holdings (${tokens.length}):\n${tokenList}` : 'No token holdings found'}`,
@@ -581,7 +581,7 @@ ${tokens.length > 0 ? `Token Holdings (${tokens.length}):\n${tokenList}` : 'No t
} }
); );
// vector_get_address — Get the agent's wallet address and balance // vector_get_address - Get the agent's wallet address and balance
server.tool( server.tool(
"vector_get_address", "vector_get_address",
"Get the Vector wallet address, balance, and token holdings derived from a mnemonic", "Get the Vector wallet address, balance, and token holdings derived from a mnemonic",
@@ -606,7 +606,7 @@ ${tokens.length > 0 ? `Token Holdings (${tokens.length}):\n${tokenList}` : 'No t
text: `# Vector Wallet Information text: `# Vector Wallet Information
Address: ${walletInfo.address} Address: ${walletInfo.address}
ADA Balance: ${walletInfo.ada} ADA AP3X Balance: ${walletInfo.ada} AP3X
UTXO Count: ${walletInfo.utxoCount} UTXO Count: ${walletInfo.utxoCount}
${walletInfo.tokens.length > 0 ? `## Token Holdings (${walletInfo.tokens.length}):\n${tokenList}` : 'No token holdings found'}`, ${walletInfo.tokens.length > 0 ? `## Token Holdings (${walletInfo.tokens.length}):\n${tokenList}` : 'No token holdings found'}`,
@@ -629,7 +629,7 @@ ${walletInfo.tokens.length > 0 ? `## Token Holdings (${walletInfo.tokens.length}
} }
); );
// vector_get_utxos — List UTxOs for an address or the wallet // vector_get_utxos - List UTxOs for an address or the wallet
server.tool( server.tool(
"vector_get_utxos", "vector_get_utxos",
"List unspent transaction outputs (UTxOs) for a Vector address or a wallet derived from a mnemonic", "List unspent transaction outputs (UTxOs) for a Vector address or a wallet derived from a mnemonic",
@@ -673,7 +673,7 @@ ${walletInfo.tokens.length > 0 ? `## Token Holdings (${walletInfo.tokens.length}
const utxoList = utxos.map((utxo, i) => { const utxoList = utxos.map((utxo, i) => {
const ada = utxo.assets['lovelace'] ? lovelaceToAda(utxo.assets['lovelace']) : '0'; const ada = utxo.assets['lovelace'] ? lovelaceToAda(utxo.assets['lovelace']) : '0';
const tokenCount = Object.keys(utxo.assets).filter(k => k !== 'lovelace').length; const tokenCount = Object.keys(utxo.assets).filter(k => k !== 'lovelace').length;
return `${i + 1}. ${utxo.txHash}#${utxo.outputIndex} — ${ada} ADA${tokenCount > 0 ? ` + ${tokenCount} token(s)` : ''}`; return `${i + 1}. ${utxo.txHash}#${utxo.outputIndex} - ${ada} AP3X${tokenCount > 0 ? ` + ${tokenCount} token(s)` : ''}`;
}).join('\n'); }).join('\n');
return { return {
@@ -698,13 +698,13 @@ ${utxoList}`,
} }
); );
// vector_send_apex — Send APEX with safety limits (or craft unsigned TX) // vector_send_apex - Send APEX with safety limits (or craft unsigned TX)
server.tool( server.tool(
"vector_send_apex", "vector_send_apex",
"Send ADA from a wallet to a recipient address. Set unsigned_only=true to return unsigned CBOR without submitting (transaction-crafter mode).", "Send AP3X from a wallet to a recipient address. Set unsigned_only=true to return unsigned CBOR without submitting (transaction-crafter mode).",
{ {
recipientAddress: z.string().describe("Recipient Vector address (addr1...)"), recipientAddress: z.string().describe("Recipient Vector address (addr1...)"),
amount: z.number().min(1).describe("Amount of ADA to send"), amount: z.number().min(1).describe("Amount of AP3X to send"),
mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the sending wallet"), mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the sending wallet"),
metadata: z.string().optional().describe("Optional transaction metadata in JSON format"), metadata: z.string().optional().describe("Optional transaction metadata in JSON format"),
unsigned_only: z.boolean().optional().default(false).describe("If true, return unsigned TX CBOR without signing or submitting"), unsigned_only: z.boolean().optional().default(false).describe("If true, return unsigned TX CBOR without signing or submitting"),
@@ -732,9 +732,9 @@ ${utxoList}`,
type: "text", type: "text",
text: `# Unsigned Transaction (Transaction-Crafter Mode) text: `# Unsigned Transaction (Transaction-Crafter Mode)
**Amount:** ${amount} ADA (${lovelaceAmount} lovelace) **Amount:** ${amount} AP3X (${lovelaceAmount} lovelace)
**To:** ${recipientAddress} **To:** ${recipientAddress}
**Estimated Fee:** ${lovelaceToAda(fee)} ADA **Estimated Fee:** ${lovelaceToAda(fee)} AP3X
**Unsigned TX CBOR:** **Unsigned TX CBOR:**
\`\`\` \`\`\`
@@ -750,12 +750,12 @@ This transaction has NOT been submitted. Sign and submit it separately.`,
return { return {
content: [{ content: [{
type: "text", type: "text",
text: `# ADA Transaction Successful text: `# AP3X Transaction Successful
Transaction Hash: ${result.txHash} Transaction Hash: ${result.txHash}
From: ${result.senderAddress} From: ${result.senderAddress}
To: ${result.recipientAddress} To: ${result.recipientAddress}
Amount: ${result.amount} ADA Amount: ${result.amount} AP3X
[View on Explorer](${result.links.explorer})`, [View on Explorer](${result.links.explorer})`,
}], }],
@@ -765,7 +765,7 @@ Amount: ${result.amount} ADA
return { return {
content: [{ content: [{
type: "text", type: "text",
text: `Failed to send ADA: ${error.message} text: `Failed to send AP3X: ${error.message}
**Troubleshooting Tips:** **Troubleshooting Tips:**
1. Check that your wallet has sufficient balance 1. Check that your wallet has sufficient balance
@@ -778,7 +778,7 @@ Amount: ${result.amount} ADA
} }
); );
// vector_send_tokens — Send native tokens with safety limits (or craft unsigned TX) // vector_send_tokens - Send native tokens with safety limits (or craft unsigned TX)
server.tool( server.tool(
"vector_send_tokens", "vector_send_tokens",
"Send Vector native tokens from a wallet to a recipient address. Set unsigned_only=true to return unsigned CBOR without submitting.", "Send Vector native tokens from a wallet to a recipient address. Set unsigned_only=true to return unsigned CBOR without submitting.",
@@ -788,7 +788,7 @@ Amount: ${result.amount} ADA
assetName: z.string().describe("Asset name (can be empty for policy-only tokens)"), assetName: z.string().describe("Asset name (can be empty for policy-only tokens)"),
amount: z.string().describe("Amount of tokens to send"), amount: z.string().describe("Amount of tokens to send"),
mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the sending wallet"), mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the sending wallet"),
adaAmount: z.number().optional().describe("Optional ADA to include (uses minimum required if not specified)"), adaAmount: z.number().optional().describe("Optional AP3X to include (uses minimum required if not specified)"),
unsigned_only: z.boolean().optional().default(false).describe("If true, return unsigned TX CBOR without signing or submitting"), unsigned_only: z.boolean().optional().default(false).describe("If true, return unsigned TX CBOR without signing or submitting"),
}, },
async ({ recipientAddress, policyId, assetName, amount, mnemonic, adaAmount, unsigned_only }) => { async ({ recipientAddress, policyId, assetName, amount, mnemonic, adaAmount, unsigned_only }) => {
@@ -821,8 +821,8 @@ Amount: ${result.amount} ADA
**Token:** ${formatAssetName(assetNameHex) || policyId.substring(0,8) + '...'} **Token:** ${formatAssetName(assetNameHex) || policyId.substring(0,8) + '...'}
**Amount:** ${amount} **Amount:** ${amount}
**To:** ${recipientAddress} **To:** ${recipientAddress}
**Included ADA:** ${lovelaceToAda(outputLovelace)} ADA **Included AP3X:** ${lovelaceToAda(outputLovelace)} AP3X
**Estimated Fee:** ${lovelaceToAda(fee)} ADA **Estimated Fee:** ${lovelaceToAda(fee)} AP3X
**Unsigned TX CBOR:** **Unsigned TX CBOR:**
\`\`\` \`\`\`
@@ -849,7 +849,7 @@ Token Details:
- Asset Name: ${result.token.name || '(none)'} - Asset Name: ${result.token.name || '(none)'}
- Amount: ${result.token.amount} - Amount: ${result.token.amount}
Included ADA: ${result.ada} ADA Included AP3X: ${result.ada} AP3X
[View on Explorer](${result.links.explorer})`, [View on Explorer](${result.links.explorer})`,
}], }],
@@ -862,7 +862,7 @@ Included ADA: ${result.ada} ADA
text: `Failed to send tokens: ${error.message} text: `Failed to send tokens: ${error.message}
**Troubleshooting Tips:** **Troubleshooting Tips:**
1. Check that your wallet has sufficient ADA and token balance 1. Check that your wallet has sufficient AP3X and token balance
2. Verify the policy ID and asset name are correct 2. Verify the policy ID and asset name are correct
3. Verify the recipient address is correct (addr1...) 3. Verify the recipient address is correct (addr1...)
4. Check spend limits with vector_get_spend_limits`, 4. Check spend limits with vector_get_spend_limits`,
@@ -872,7 +872,7 @@ Included ADA: ${result.ada} ADA
} }
); );
// vector_get_spend_limits — Check safety layer status // vector_get_spend_limits - Check safety layer status
server.tool( server.tool(
"vector_get_spend_limits", "vector_get_spend_limits",
"Check current spend limits and remaining daily budget", "Check current spend limits and remaining daily budget",
@@ -887,7 +887,7 @@ Included ADA: ${result.ada} ADA
const log = safetyLayer.getAuditLog(); const log = safetyLayer.getAuditLog();
const recentTxs = log.slice(-5).reverse().map((entry) => const recentTxs = log.slice(-5).reverse().map((entry) =>
`- ${entry.timestamp}: ${lovelaceToAda(entry.amountLovelace)} ADA → ${entry.recipient.substring(0, 20)}... (${entry.txHash.substring(0, 16)}...)` `- ${entry.timestamp}: ${lovelaceToAda(entry.amountLovelace)} AP3X → ${entry.recipient.substring(0, 20)}... (${entry.txHash.substring(0, 16)}...)`
).join('\n'); ).join('\n');
return { return {
@@ -895,10 +895,10 @@ Included ADA: ${result.ada} ADA
type: "text", type: "text",
text: `# Vector Spend Limits text: `# Vector Spend Limits
Per-Transaction Limit: ${lovelaceToAda(status.perTransactionLimit)} ADA Per-Transaction Limit: ${lovelaceToAda(status.perTransactionLimit)} AP3X
Daily Limit: ${lovelaceToAda(status.dailyLimit)} ADA Daily Limit: ${lovelaceToAda(status.dailyLimit)} AP3X
Daily Spent: ${lovelaceToAda(status.dailySpent)} ADA Daily Spent: ${lovelaceToAda(status.dailySpent)} AP3X
Daily Remaining: ${lovelaceToAda(status.dailyRemaining)} ADA Daily Remaining: ${lovelaceToAda(status.dailyRemaining)} AP3X
Resets At: ${status.resetTime} Resets At: ${status.resetTime}
${log.length > 0 ? `## Recent Transactions (last ${Math.min(5, log.length)}):\n${recentTxs}` : 'No transactions recorded yet.'}`, ${log.length > 0 ? `## Recent Transactions (last ${Math.min(5, log.length)}):\n${recentTxs}` : 'No transactions recorded yet.'}`,
@@ -916,14 +916,14 @@ ${log.length > 0 ? `## Recent Transactions (last ${Math.min(5, log.length)}):\n$
} }
); );
// vector_build_transaction — Build a complex multi-output transaction // vector_build_transaction - Build a complex multi-output transaction
server.tool( server.tool(
"vector_build_transaction", "vector_build_transaction",
"Build a complex multi-output transaction with metadata. Set submit=true to sign and submit, or false to return unsigned CBOR for review.", "Build a complex multi-output transaction with metadata. Set submit=true to sign and submit, or false to return unsigned CBOR for review.",
{ {
outputs: z.array(z.object({ outputs: z.array(z.object({
address: z.string().describe("Recipient Vector address"), address: z.string().describe("Recipient Vector address"),
lovelace: z.number().describe("Amount in lovelace (1 ADA = 1,000,000 lovelace)"), lovelace: z.number().describe("Amount in lovelace (1 AP3X = 1,000,000 lovelace)"),
assets: z.record(z.string()).optional().describe("Optional native assets: { 'policyId+assetNameHex': 'quantity' }"), assets: z.record(z.string()).optional().describe("Optional native assets: { 'policyId+assetNameHex': 'quantity' }"),
})).min(1).describe("Transaction outputs"), })).min(1).describe("Transaction outputs"),
mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the signing wallet"), mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the signing wallet"),
@@ -945,9 +945,9 @@ ${log.length > 0 ? `## Recent Transactions (last ${Math.min(5, log.length)}):\n$
text: `# Transaction Submitted text: `# Transaction Submitted
Transaction Hash: ${result.txHash} Transaction Hash: ${result.txHash}
Fee: ${result.feeAda} ADA Fee: ${result.feeAda} AP3X
Outputs: ${result.outputCount} Outputs: ${result.outputCount}
Total ADA Sent: ${result.totalAda} ADA Total AP3X Sent: ${result.totalAda} AP3X
[View on Explorer](${result.links?.explorer})`, [View on Explorer](${result.links?.explorer})`,
}], }],
@@ -960,9 +960,9 @@ Total ADA Sent: ${result.totalAda} ADA
text: `# Transaction Built (Not Submitted) text: `# Transaction Built (Not Submitted)
Transaction Hash: ${result.txHash} Transaction Hash: ${result.txHash}
Fee: ${result.feeAda} ADA Fee: ${result.feeAda} AP3X
Outputs: ${result.outputCount} Outputs: ${result.outputCount}
Total ADA: ${result.totalAda} ADA Total AP3X: ${result.totalAda} AP3X
CBOR (hex): ${result.txCbor.substring(0, 200)}${result.txCbor.length > 200 ? '...' : ''} CBOR (hex): ${result.txCbor.substring(0, 200)}${result.txCbor.length > 200 ? '...' : ''}
@@ -978,7 +978,7 @@ Use vector_dry_run with this CBOR to simulate, or call vector_build_transaction
**Troubleshooting Tips:** **Troubleshooting Tips:**
1. Verify all recipient addresses are valid (addr1...) 1. Verify all recipient addresses are valid (addr1...)
2. Ensure wallet has enough ADA for outputs + fees 2. Ensure wallet has enough AP3X for outputs + fees
3. Check spend limits with vector_get_spend_limits`, 3. Check spend limits with vector_get_spend_limits`,
}], }],
}; };
@@ -986,10 +986,10 @@ Use vector_dry_run with this CBOR to simulate, or call vector_build_transaction
} }
); );
// vector_dry_run — Simulate a transaction without submitting // vector_dry_run - Simulate a transaction without submitting
server.tool( server.tool(
"vector_dry_run", "vector_dry_run",
"Simulate a transaction without submitting — returns fee estimate and validation result", "Simulate a transaction without submitting - returns fee estimate and validation result",
{ {
txCbor: z.string().optional().describe("Hex-encoded CBOR of a built transaction to evaluate"), txCbor: z.string().optional().describe("Hex-encoded CBOR of a built transaction to evaluate"),
outputs: z.array(z.object({ outputs: z.array(z.object({
@@ -1071,7 +1071,7 @@ Use vector_dry_run with this CBOR to simulate, or call vector_build_transaction
executionUnits: (totalMemory > 0 || totalCpu > 0) ? { memory: totalMemory, cpu: totalCpu } : undefined, executionUnits: (totalMemory > 0 || totalCpu > 0) ? { memory: totalMemory, cpu: totalCpu } : undefined,
}; };
} catch (evalErr) { } catch (evalErr) {
// evaluateTransaction failed — still return fee if we built the tx // evaluateTransaction failed - still return fee if we built the tx
if (feeFromBuild) { if (feeFromBuild) {
evalResult = { evalResult = {
valid: true, valid: true,
@@ -1095,7 +1095,7 @@ Use vector_dry_run with this CBOR to simulate, or call vector_build_transaction
text: `# Dry Run Result text: `# Dry Run Result
Valid: ${evalResult.valid ? 'Yes' : 'No'} Valid: ${evalResult.valid ? 'Yes' : 'No'}
Estimated Fee: ${evalResult.feeAda} ADA (${evalResult.fee} lovelace) Estimated Fee: ${evalResult.feeAda} AP3X (${evalResult.fee} lovelace)
${evalResult.executionUnits ? `Execution Units: Memory ${evalResult.executionUnits.memory}, CPU ${evalResult.executionUnits.cpu}` : ''} ${evalResult.executionUnits ? `Execution Units: Memory ${evalResult.executionUnits.memory}, CPU ${evalResult.executionUnits.cpu}` : ''}
${evalResult.error ? `\nNote: ${evalResult.error}` : ''} ${evalResult.error ? `\nNote: ${evalResult.error}` : ''}
@@ -1114,7 +1114,7 @@ No transaction was submitted to the network.`,
} }
); );
// vector_get_transaction_history — Get transaction history via Koios // vector_get_transaction_history - Get transaction history via Koios
server.tool( server.tool(
"vector_get_transaction_history", "vector_get_transaction_history",
"Get transaction history for a Vector address via Koios indexed queries", "Get transaction history for a Vector address via Koios indexed queries",
@@ -1156,7 +1156,7 @@ No transaction was submitted to the network.`,
const txList = txs.map((tx, i) => { const txList = txs.map((tx, i) => {
const feeAda = tx.fee ? lovelaceToAda(tx.fee) : 'N/A'; const feeAda = tx.fee ? lovelaceToAda(tx.fee) : 'N/A';
return `${i + 1}. ${tx.txHash}\n Block: ${tx.blockHeight} | Time: ${tx.blockTime} | Fee: ${feeAda} ADA`; return `${i + 1}. ${tx.txHash}\n Block: ${tx.blockHeight} | Time: ${tx.blockTime} | Fee: ${feeAda} AP3X`;
}).join('\n\n'); }).join('\n\n');
return { return {
@@ -1188,7 +1188,7 @@ ${txList}
} }
); );
// vector_deploy_contract — Deploy a Plutus/Aiken smart contract // vector_deploy_contract - Deploy a Plutus/Aiken smart contract
server.tool( server.tool(
"vector_deploy_contract", "vector_deploy_contract",
"Deploy a Plutus/Aiken smart contract to Vector by sending funds to its script address", "Deploy a Plutus/Aiken smart contract to Vector by sending funds to its script address",
@@ -1197,7 +1197,7 @@ ${txList}
scriptType: z.enum(["PlutusV1", "PlutusV2", "PlutusV3"]).describe("Script version"), scriptType: z.enum(["PlutusV1", "PlutusV2", "PlutusV3"]).describe("Script version"),
mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the deploying wallet"), mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the deploying wallet"),
initialDatum: z.string().optional().describe("Initial datum as CBOR hex. Use 'd87980' for void/unit datum. Defaults to void if omitted."), initialDatum: z.string().optional().describe("Initial datum as CBOR hex. Use 'd87980' for void/unit datum. Defaults to void if omitted."),
lovelaceAmount: z.number().optional().describe("ADA to lock at the script address in lovelace (default: 2,000,000 = 2 ADA)"), lovelaceAmount: z.number().optional().describe("AP3X to lock at the script address in lovelace (default: 2,000,000 = 2 AP3X)"),
}, },
async ({ scriptCbor, scriptType, mnemonic, initialDatum, lovelaceAmount }) => { async ({ scriptCbor, scriptType, mnemonic, initialDatum, lovelaceAmount }) => {
const rateCheck = rateLimiter.check(); const rateCheck = rateLimiter.check();
@@ -1237,7 +1237,7 @@ Funds locked at the script address. Use vector_interact_contract to interact wit
**Troubleshooting Tips:** **Troubleshooting Tips:**
1. Verify the script CBOR is valid hex (compiled Aiken or Plutus output) 1. Verify the script CBOR is valid hex (compiled Aiken or Plutus output)
2. Ensure wallet has sufficient ADA for the locked amount + fees 2. Ensure wallet has sufficient AP3X for the locked amount + fees
3. Check that the script type matches the compiled version (PlutusV1/V2/V3) 3. Check that the script type matches the compiled version (PlutusV1/V2/V3)
4. Check spend limits with vector_get_spend_limits`, 4. Check spend limits with vector_get_spend_limits`,
}], }],
@@ -1246,10 +1246,10 @@ Funds locked at the script address. Use vector_interact_contract to interact wit
} }
); );
// vector_interact_contract — Interact with a deployed smart contract // vector_interact_contract - Interact with a deployed smart contract
server.tool( server.tool(
"vector_interact_contract", "vector_interact_contract",
"Interact with a deployed Plutus/Aiken smart contract — lock funds or spend from it", "Interact with a deployed Plutus/Aiken smart contract - lock AP3X or spend from it",
{ {
scriptCbor: z.string().describe("Compiled Plutus/Aiken script in CBOR hex"), scriptCbor: z.string().describe("Compiled Plutus/Aiken script in CBOR hex"),
scriptType: z.enum(["PlutusV1", "PlutusV2", "PlutusV3"]).describe("Script version"), scriptType: z.enum(["PlutusV1", "PlutusV2", "PlutusV3"]).describe("Script version"),
@@ -1257,7 +1257,7 @@ Funds locked at the script address. Use vector_interact_contract to interact wit
mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the wallet"), mnemonic: z.string().describe("15 or 24-word BIP39 mnemonic for the wallet"),
redeemer: z.string().optional().describe("Redeemer as CBOR hex (required for spend, use 'd87980' for void)"), redeemer: z.string().optional().describe("Redeemer as CBOR hex (required for spend, use 'd87980' for void)"),
datum: z.string().optional().describe("Datum as CBOR hex (required for lock, use 'd87980' for void)"), datum: z.string().optional().describe("Datum as CBOR hex (required for lock, use 'd87980' for void)"),
lovelaceAmount: z.number().optional().describe("Lovelace to lock (for lock action, default: 2,000,000 = 2 ADA)"), lovelaceAmount: z.number().optional().describe("Lovelace to lock (for lock action, default: 2,000,000 = 2 AP3X)"),
utxoRef: z.object({ utxoRef: z.object({
txHash: z.string(), txHash: z.string(),
outputIndex: z.number(), outputIndex: z.number(),
@@ -1307,8 +1307,8 @@ Funds ${actionVerb} the script address.
**Troubleshooting Tips:** **Troubleshooting Tips:**
1. For 'spend': ensure the script address has UTxOs and the redeemer satisfies the validator 1. For 'spend': ensure the script address has UTxOs and the redeemer satisfies the validator
2. For 'lock': ensure wallet has sufficient ADA and the datum matches the script's expectations 2. For 'lock': ensure wallet has sufficient AP3X and the datum matches the script's expectations
3. Spending requires collateral — ensure wallet has a pure-ADA UTxO (no native tokens) 3. Spending requires collateral - ensure wallet has a pure-AP3X UTxO (no native tokens)
4. Verify the script CBOR matches the deployed script exactly 4. Verify the script CBOR matches the deployed script exactly
5. Check spend limits with vector_get_spend_limits`, 5. Check spend limits with vector_get_spend_limits`,
}], }],