Fix BigInt crash in protocol parameter parsing, add docker-compose

Protocol parameter fields (minFeeA, minFeeB, maxTxSize, maxValSize)
lacked fallback defaults, causing "Cannot convert undefined to a BigInt"
when Lucid-Evolution processed them. Added safe defaults sourced from
Vector public testnet and updated deposit values to match. Made
lovelaceToAda() defensive against undefined/null. Added diagnostic
logging to getWalletInfo and getProtocolParameters error paths.

Converted Dockerfile to multi-stage build and added docker-compose.yml
with inline Vector testnet environment config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
david
2026-03-31 13:26:49 +02:00
parent 96a2d12005
commit 8ff02f244e
4 changed files with 64 additions and 26 deletions

View File

@@ -1,7 +1,15 @@
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY tsup.config* tsconfig* ./
COPY src/ ./src/
RUN npm run build
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY build/ ./build/
COPY --from=builder /app/build/ ./build/
EXPOSE 3000
CMD ["node", "build/index.js"]

12
docker-compose.yml Normal file
View File

@@ -0,0 +1,12 @@
services:
vector-mcp:
build: .
container_name: vector-mcp
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
environment:
- VECTOR_OGMIOS_URL=https://ogmios.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_EXPLORER_URL=https://vector.testnet.apexscan.org

View File

@@ -64,30 +64,39 @@ export class OgmiosProvider implements Provider {
async getProtocolParameters(): Promise<ProtocolParameters> {
const result = await this.rpc('queryLedgerState/protocolParameters');
// Map Ogmios v6 response to Lucid's ProtocolParameters format
return {
minFeeA: result.minFeeCoefficient,
minFeeB: result.minFeeConstant?.ada?.lovelace ?? result.minFeeConstant,
maxTxSize: result.maxTransactionSize?.bytes ?? result.maxTransactionSize,
maxValSize: result.maxValueSize?.bytes ?? result.maxValueSize,
keyDeposit: BigInt(result.stakeCredentialDeposit?.ada?.lovelace ?? result.stakeCredentialDeposit ?? 2000000),
poolDeposit: BigInt(result.stakePoolDeposit?.ada?.lovelace ?? result.stakePoolDeposit ?? 500000000),
priceMem: result.scriptExecutionPrices?.memory
? this.parseFraction(result.scriptExecutionPrices.memory)
: (result.prices?.memory ?? 0.0577),
priceStep: result.scriptExecutionPrices?.cpu
? this.parseFraction(result.scriptExecutionPrices.cpu)
: (result.prices?.steps ?? 0.0000721),
maxTxExMem: BigInt(result.maxExecutionUnitsPerTransaction?.memory ?? 14000000),
maxTxExSteps: BigInt(result.maxExecutionUnitsPerTransaction?.cpu ?? 10000000000),
coinsPerUtxoByte: BigInt(result.minUtxoDepositCoefficient ?? result.coinsPerUtxoByte ?? 4310),
collateralPercentage: result.collateralPercentage ?? 150,
maxCollateralInputs: result.maxCollateralInputs ?? 3,
costModels: this.parseCostModels(result.plutusCostModels ?? result.costModels ?? {}),
minFeeRefScriptCostPerByte: result.minFeeReferenceScripts?.base ?? 15,
drepDeposit: BigInt(result.delegateRepresentativeDeposit?.ada?.lovelace ?? 500000000),
govActionDeposit: BigInt(result.governanceActionDeposit?.ada?.lovelace ?? 100000000000),
} as ProtocolParameters;
try {
// Map Ogmios v6 response to Lucid's ProtocolParameters format
// Defaults are sourced from the Vector public testnet (2026-03-31)
return {
minFeeA: result.minFeeCoefficient ?? 45,
minFeeB: result.minFeeConstant?.ada?.lovelace
?? result.minFeeConstant?.lovelace
?? (typeof result.minFeeConstant === 'number' ? result.minFeeConstant : 156253),
maxTxSize: result.maxTransactionSize?.bytes ?? result.maxTransactionSize ?? 16384,
maxValSize: result.maxValueSize?.bytes ?? result.maxValueSize ?? 5000,
keyDeposit: BigInt(result.stakeCredentialDeposit?.ada?.lovelace ?? result.stakeCredentialDeposit ?? 500000000),
poolDeposit: BigInt(result.stakePoolDeposit?.ada?.lovelace ?? result.stakePoolDeposit ?? 5000000000000),
priceMem: result.scriptExecutionPrices?.memory
? this.parseFraction(result.scriptExecutionPrices.memory)
: (result.prices?.memory ?? 0.0577),
priceStep: result.scriptExecutionPrices?.cpu
? this.parseFraction(result.scriptExecutionPrices.cpu)
: (result.prices?.steps ?? 0.0000721),
maxTxExMem: BigInt(result.maxExecutionUnitsPerTransaction?.memory ?? 16000000),
maxTxExSteps: BigInt(result.maxExecutionUnitsPerTransaction?.cpu ?? 10000000000),
coinsPerUtxoByte: BigInt(result.minUtxoDepositCoefficient ?? result.coinsPerUtxoByte ?? 4310),
collateralPercentage: result.collateralPercentage ?? 150,
maxCollateralInputs: result.maxCollateralInputs ?? 3,
costModels: this.parseCostModels(result.plutusCostModels ?? result.costModels ?? {}),
minFeeRefScriptCostPerByte: result.minFeeReferenceScripts?.base ?? 15,
drepDeposit: BigInt(result.delegateRepresentativeDeposit?.ada?.lovelace ?? 1000000000000),
govActionDeposit: BigInt(result.governanceActionDeposit?.ada?.lovelace ?? 1000000000),
} as ProtocolParameters;
} catch (err) {
console.error('[OgmiosProvider] Protocol parameter mapping failed:', err);
console.error('[OgmiosProvider] Raw Ogmios result:', JSON.stringify(result, null, 2));
throw err;
}
}
private parseFraction(value: string | number): number {

View File

@@ -43,7 +43,12 @@ const VECTOR_EXPLORER_URL = process.env.VECTOR_EXPLORER_URL || 'https://vector.t
// Helper function to format ADA amounts
function lovelaceToAda(lovelace: string | number | bigint): string {
return (Number(BigInt(String(lovelace))) / 1_000_000).toFixed(6);
if (lovelace === undefined || lovelace === null) return '0.000000';
try {
return (Number(BigInt(String(lovelace))) / 1_000_000).toFixed(6);
} catch {
return '0.000000';
}
}
// Helper function to format asset name
@@ -98,9 +103,13 @@ async function initLucid(mnemonic: string, accountIndex: number = 0) {
// Get wallet info
export async function getWalletInfo(mnemonic: string, accountIndex: number = 0): Promise<VectorWalletInfo> {
console.error('[getWalletInfo] Initializing Lucid...');
const lucid = await initLucid(mnemonic, accountIndex);
console.error('[getWalletInfo] Getting address...');
const address = await lucid.wallet().address();
console.error('[getWalletInfo] Querying UTxOs...');
const utxos = await lucid.utxosAt(address);
console.error(`[getWalletInfo] Found ${utxos.length} UTxOs`);
let adaBalance = '0';
let tokenBalances: VectorToken[] = [];