diff --git a/packages/shared/src/cbor/AdvertDatum.ts b/packages/shared/src/cbor/AdvertDatum.ts index 3382290..b71770a 100644 --- a/packages/shared/src/cbor/AdvertDatum.ts +++ b/packages/shared/src/cbor/AdvertDatum.ts @@ -118,19 +118,24 @@ export function encodeAdvertDatum(d: AdvertDatum): string { throw new Error(`unknown AdvertStatus: ${String(d.status)}`); })(); + // cbor-x encodes JS Number as float64 (`fb` prefix) for values that don't + // fit in CBOR's compact int forms — and Plutus Data has NO float type, so + // CML's PlutusData.from_cbor_hex panics with "RuntimeError: unreachable" + // when it sees one. Coerce numeric fields to BigInt so cbor-x always emits + // CBOR major-type-0/1 integers. Mirrors the intAsBig pattern in EscrowDatum. const cbor = plutusTag(121, [ hexToBytes(d.supplier_pkh), utf8Bytes(d.capability_id), utf8Bytes(d.model), - d.max_output_tokens, - d.max_processing_ms, + BigInt(d.max_output_tokens), + BigInt(d.max_processing_ms), d.price_lovelace, d.supplier_bond_lovelace, d.buyer_bond_lovelace, utf8Bytes(d.endpoint_url), utf8Bytes(d.detail_uri), hexToBytes(d.detail_hash), - d.advertised_at, + BigInt(d.advertised_at), statusTag, ]); diff --git a/packages/shared/src/tx/advert/postAdvert.ts b/packages/shared/src/tx/advert/postAdvert.ts index df3d32b..61406cf 100644 --- a/packages/shared/src/tx/advert/postAdvert.ts +++ b/packages/shared/src/tx/advert/postAdvert.ts @@ -19,6 +19,7 @@ import { loadBlueprint } from "../blueprint.js"; import { encodeTxBody, sha256Hex } from "../internal/testTxBody.js"; import { mockSlotToWallclockMs } from "../internal/constants.js"; import { detectCborBackend } from "../internal/cborBackend.js"; +import type { LiveOgmiosProvider } from "../../chain/LiveOgmiosProvider.js"; const FIVE_MIN_MS = 5 * 60 * 1000; @@ -64,6 +65,19 @@ export async function buildPostAdvertTx( } // 4. Construct tx body. + // Live path: route to lucid-evolution so the on-chain submission carries + // valid Conway-era CBOR. Mock path keeps the JSON-in-hex synthetic body. + if (isLive) { + const liveCborPath = "../internal/liveCbor.js"; + const { buildLiveTxForAdvert } = await import(/* @vite-ignore */ liveCborPath); + return buildLiveTxForAdvert({ + chain: chain as LiveOgmiosProvider, + walletKey, + advertDatum, + deposit_lovelace, + }); + } + const blueprint = loadBlueprint(); const advertScriptAddress = blueprint.advertScriptAddress(0); diff --git a/packages/shared/src/tx/internal/liveCbor.ts b/packages/shared/src/tx/internal/liveCbor.ts index 6e3c5ed..3a9f4c4 100644 --- a/packages/shared/src/tx/internal/liveCbor.ts +++ b/packages/shared/src/tx/internal/liveCbor.ts @@ -342,8 +342,18 @@ async function buildSpendOpenOrClaimedTx(opts: { // Let lucid pick coins + compute fee normally; production wallets have // multiple real UTxOs (no need for the test-side leftover-as-fee hack). + // + // localUPLCEval: false — delegate Plutus V3 phase-2 evaluation to Ogmios + // (which uses cardano-node's evaluator). lucid 0.4.30's CML WASM UPLC + // interpreter has a false-rejection bug for our V3 spend pattern: it + // rejects valid txs with "failed script execution Spend[0] the validator + // crashed / exited prematurely" while the chain itself accepts them + // without complaint. Routing eval to Ogmios sidesteps the WASM bug AND + // produces correct ex-units. The provider already implements evaluateTx + // (OgmiosLucidProvider.evaluateTx → JSON-RPC evaluateTransaction). const completed = await txBuilder.complete({ presetWalletInputs: realWalletUtxos, + localUPLCEval: false, }); signed = await completed.sign.withWallet().complete(); } catch (err) {