diff --git a/.changeset/fix-provider-error-handling.md b/.changeset/fix-provider-error-handling.md new file mode 100644 index 00000000..bd075ba9 --- /dev/null +++ b/.changeset/fix-provider-error-handling.md @@ -0,0 +1,5 @@ +--- +"@evolution-sdk/evolution": patch +--- + +Fix Blockfrost evaluateTx failing on multi-asset UTxOs by correcting the value format sent to the Ogmios endpoint. Standardize error handling across all providers with consistent catchAll + wrapError pattern. Add JSONWSP fault detection to Blockfrost evaluation responses. Accept both CBOR tag-258 and plain array encodings in TransactionBody decoding. diff --git a/packages/evolution/src/TransactionBody.ts b/packages/evolution/src/TransactionBody.ts index def47495..d3bad08b 100644 --- a/packages/evolution/src/TransactionBody.ts +++ b/packages/evolution/src/TransactionBody.ts @@ -191,7 +191,8 @@ const decodeAuxiliaryDataHash = ParseResult.decodeEither(AuxiliaryDataHash.FromB const decodeScriptDataHash = ParseResult.decodeEither(ScriptDataHash.FromBytes) const decodeKeyHash = ParseResult.decodeEither(KeyHash.FromBytes) -const decodeInputs = ParseResult.decodeUnknownEither(CBOR.tag(258, Schema.Array(TransactionInput.FromCDDL))) +const decodeTaggedInputs = ParseResult.decodeUnknownEither(CBOR.tag(258, Schema.Array(TransactionInput.FromCDDL))) +const decodeUntaggedInputs = ParseResult.decodeUnknownEither(Schema.Array(TransactionInput.FromCDDL)) /** * CDDL schema for TransactionBody struct structure. @@ -314,10 +315,12 @@ export const FromCDDL = Schema.transformOrFail(CDDLSchema, Schema.typeSchema(Tra }), decode: (fromA) => E.gen(function* () { - // Required fields - access via helper - const inputsTag = fromA.get(0n) - const decodedInputs = yield* decodeInputs(inputsTag) - const inputs = decodedInputs.value + // Required fields - accept both tag-258 (Conway) and plain array (Babbage) + const inputsRaw = fromA.get(0n) + const taggedResult = decodeTaggedInputs(inputsRaw) + const inputs = E.isRight(taggedResult) + ? taggedResult.right.value + : yield* decodeUntaggedInputs(inputsRaw) // const inputsArray = inputsTag.value // const inputsLen = inputsArray.length @@ -370,14 +373,16 @@ export const FromCDDL = Schema.transformOrFail(CDDLSchema, Schema.typeSchema(Tra const scriptDataHashBytes = fromA.get(11n) as Uint8Array | undefined const scriptDataHash = scriptDataHashBytes ? yield* decodeScriptDataHash(scriptDataHashBytes) : undefined - const collateralInputsTag = fromA.get(13n) as - | { - _tag: "Tag" - tag: 258 - value: ReadonlyArray - } + // Accept both tag-258 (Conway) and plain array (Babbage) for collateral inputs + const collateralInputsRaw = fromA.get(13n) as + | { _tag: "Tag"; tag: 258; value: ReadonlyArray } + | ReadonlyArray | undefined - const collateralInputsArray = collateralInputsTag ? collateralInputsTag.value : undefined + const collateralInputsArray = collateralInputsRaw + ? (collateralInputsRaw as any)._tag === "Tag" + ? (collateralInputsRaw as any).value + : collateralInputsRaw + : undefined let collateralInputs: NonEmptyArray | undefined if (collateralInputsArray) { const len = collateralInputsArray.length @@ -388,14 +393,16 @@ export const FromCDDL = Schema.transformOrFail(CDDLSchema, Schema.typeSchema(Tra collateralInputs = arr as NonEmptyArray } - const requiredSignersTag = fromA.get(14n) as - | { - _tag: "Tag" - tag: 258 - value: ReadonlyArray - } + // Accept both tag-258 (Conway) and plain array (Babbage) for required signers + const requiredSignersRaw = fromA.get(14n) as + | { _tag: "Tag"; tag: 258; value: ReadonlyArray } + | ReadonlyArray | undefined - const requiredSignersArray = requiredSignersTag ? requiredSignersTag.value : undefined + const requiredSignersArray = requiredSignersRaw + ? (requiredSignersRaw as any)._tag === "Tag" + ? (requiredSignersRaw as any).value + : requiredSignersRaw + : undefined let requiredSigners: NonEmptyArray | undefined if (requiredSignersArray) { const len = requiredSignersArray.length @@ -411,14 +418,16 @@ export const FromCDDL = Schema.transformOrFail(CDDLSchema, Schema.typeSchema(Tra const collateralReturn = collateralReturnData ? yield* decodeTxOutput(collateralReturnData) : undefined const totalCollateral = fromA.get(17n) as Coin.Coin | undefined - const referenceInputsTag = fromA.get(18n) as - | { - _tag: "Tag" - tag: 258 - value: ReadonlyArray - } + // Accept both tag-258 (Conway) and plain array (Babbage) for reference inputs + const referenceInputsRaw = fromA.get(18n) as + | { _tag: "Tag"; tag: 258; value: ReadonlyArray } + | ReadonlyArray | undefined - const referenceInputsArray = referenceInputsTag ? referenceInputsTag.value : undefined + const referenceInputsArray: ReadonlyArray | undefined = referenceInputsRaw + ? (referenceInputsRaw as any)._tag === "Tag" + ? (referenceInputsRaw as any).value + : referenceInputsRaw + : undefined let referenceInputs: NonEmptyArray | undefined if (referenceInputsArray) { const len = referenceInputsArray.length @@ -430,15 +439,15 @@ export const FromCDDL = Schema.transformOrFail(CDDLSchema, Schema.typeSchema(Tra } const votingProceduresData = fromA.get(19n) as typeof VotingProcedures.CDDLSchema.Type | undefined const votingProcedures = votingProceduresData ? yield* decodeVotingProcedures(votingProceduresData) : undefined - const proposalProceduresTag = fromA.get(20n) as - | { - _tag: "Tag" - tag: 258 - value: ReadonlyArray - } + // Accept both tag-258 (Conway) and plain array (Babbage) for proposal procedures + const proposalProceduresRaw = fromA.get(20n) as + | { _tag: "Tag"; tag: 258; value: ReadonlyArray } + | ReadonlyArray | undefined - const proposalProceduresArray = proposalProceduresTag - ? (proposalProceduresTag.value as ReadonlyArray) + const proposalProceduresArray: ReadonlyArray | undefined = proposalProceduresRaw + ? (proposalProceduresRaw as any)._tag === "Tag" + ? (proposalProceduresRaw as any).value + : proposalProceduresRaw : undefined const proposalProcedures = proposalProceduresArray ? new ProposalProcedures.ProposalProcedures({ diff --git a/packages/evolution/src/sdk/provider/internal/Blockfrost.ts b/packages/evolution/src/sdk/provider/internal/Blockfrost.ts index 46d1b4e1..c271e308 100644 --- a/packages/evolution/src/sdk/provider/internal/Blockfrost.ts +++ b/packages/evolution/src/sdk/provider/internal/Blockfrost.ts @@ -3,13 +3,14 @@ * Internal module for Blockfrost provider implementation */ -import { Schema } from "effect" +import { Effect, Schema } from "effect" import * as CoreAssets from "../../../Assets/index.js" import * as PoolKeyHash from "../../../PoolKeyHash.js" import * as Redeemer from "../../../Redeemer.js" import type { EvalRedeemer } from "../../EvalRedeemer.js" import type * as Provider from "../Provider.js" +import { ProviderError } from "../Provider.js" // ============================================================================ // Blockfrost API Response Schemas @@ -158,7 +159,7 @@ export const JsonwspOgmiosEvaluationResponse = Schema.Struct({ version: Schema.optional(Schema.String), servicename: Schema.optional(Schema.String), methodname: Schema.optional(Schema.String), - result: Schema.Struct({ + result: Schema.optional(Schema.Struct({ EvaluationResult: Schema.optional( Schema.Record({ key: Schema.String, // "spend:0", "mint:1", etc. @@ -169,7 +170,11 @@ export const JsonwspOgmiosEvaluationResponse = Schema.Struct({ }) ), EvaluationFailure: Schema.optional(Schema.Unknown) - }), + })), + fault: Schema.optional(Schema.Struct({ + code: Schema.optional(Schema.String), + string: Schema.optional(Schema.String) + })), reflection: Schema.optional(Schema.Unknown) }) @@ -258,17 +263,48 @@ export const transformDelegation = (blockfrostDelegation: BlockfrostDelegation): */ export const transformJsonwspOgmiosEvaluationResult = ( jsonwspResponse: JsonwspOgmiosEvaluationResponse -): Array => { +): Effect.Effect, ProviderError> => { + // Handle JSONWSP fault response (Ogmios backend error) + if (jsonwspResponse.type === "jsonwsp/fault") { + const faultMessage = jsonwspResponse.fault?.string ?? "unknown fault" + return Effect.fail( + new ProviderError({ + message: `Blockfrost evaluation fault: ${faultMessage}`, + cause: jsonwspResponse + }) + ) + } + + // Handle missing result field + if (!jsonwspResponse.result) { + return Effect.fail( + new ProviderError({ + message: `Blockfrost evaluation returned no result`, + cause: jsonwspResponse + }) + ) + } + // Check for evaluation failure if (jsonwspResponse.result.EvaluationFailure) { const failure = jsonwspResponse.result.EvaluationFailure - throw new Error(`Script evaluation failed: ${JSON.stringify(failure)}`) + return Effect.fail( + new ProviderError({ + message: `Blockfrost script evaluation failed`, + cause: failure + }) + ) } // Handle success case const evaluationResult = jsonwspResponse.result.EvaluationResult if (!evaluationResult) { - throw new Error("No evaluation result returned from Blockfrost") + return Effect.fail( + new ProviderError({ + message: `Blockfrost evaluation returned no result`, + cause: "No EvaluationResult in response" + }) + ) } const result: Array = [] @@ -291,5 +327,5 @@ export const transformJsonwspOgmiosEvaluationResult = ( }) } - return result + return Effect.succeed(result) } diff --git a/packages/evolution/src/sdk/provider/internal/BlockfrostEffect.ts b/packages/evolution/src/sdk/provider/internal/BlockfrostEffect.ts index 533cfdaa..fd36e9bf 100644 --- a/packages/evolution/src/sdk/provider/internal/BlockfrostEffect.ts +++ b/packages/evolution/src/sdk/provider/internal/BlockfrostEffect.ts @@ -7,12 +7,14 @@ import { HttpClientError } from "@effect/platform" import { Effect, Schedule, Schema } from "effect" import * as CoreAddress from "../../../Address.js" +import * as AssetName from "../../../AssetName.js" import * as Bytes from "../../../Bytes.js" import type * as Credential from "../../../Credential.js" import * as PlutusData from "../../../Data.js" import * as DatumHash from "../../../DatumHash.js" import type * as DatumOption from "../../../DatumOption.js" import * as InlineDatum from "../../../InlineDatum.js" +import * as NativeScripts from "../../../NativeScripts.js" import * as PlutusV1 from "../../../PlutusV1.js" import * as PlutusV2 from "../../../PlutusV2.js" import * as PlutusV3 from "../../../PlutusV3.js" @@ -26,7 +28,6 @@ import type * as Provider from "../Provider.js" import { ProviderError } from "../Provider.js" import * as Blockfrost from "./Blockfrost.js" import * as HttpUtils from "./HttpUtils.js" -import * as Ogmios from "./Ogmios.js" // ============================================================================ // Rate Limiting Configuration @@ -51,13 +52,15 @@ const createHeaders = (projectId?: string) => ({ }) /** - * Wrap HTTP errors into ProviderError + * Wrap errors into ProviderError */ -const wrapError = (operation: string) => (error: unknown) => - new ProviderError({ - message: `Blockfrost ${operation} failed. ${(error as Error).message}`, - cause: error - }) +const wrapError = (operation: string) => (cause: unknown) => + Effect.fail( + new ProviderError({ + message: `Blockfrost ${operation} failed`, + cause + }) + ) /** * Check if an error is a 404 Not Found response @@ -81,6 +84,91 @@ const getAddressPath = (addressOrCredential: CoreAddress.Address | Credential.Cr return addressOrCredential.toString() } +const toBlockfrostValue = ( + assets: CoreUTxO.UTxO["assets"] +): Record => { + const value: Record = { + coins: Number(assets.lovelace) + } + + if (assets.multiAsset) { + for (const [policyId, assetMap] of assets.multiAsset.map.entries()) { + const policyIdHex = Bytes.toHex(policyId.hash) + const assetRecord: Record = {} + + for (const [assetName, quantity] of assetMap.entries()) { + assetRecord[AssetName.toHex(assetName)] = Number(quantity) + } + + if (Object.keys(assetRecord).length > 0) { + value[policyIdHex] = assetRecord + } + } + } + + return value +} + +const toBlockfrostDatum = ( + datumOption: DatumOption.DatumOption | undefined +): { datumHash?: string; datum?: string } => { + if (!datumOption) { + return {} + } + + if (datumOption._tag === "DatumHash") { + return { datumHash: Bytes.toHex(datumOption.hash) } + } + + return { datum: PlutusData.toCBORHex(datumOption.data) } +} + +const toBlockfrostScript = ( + script: Script.Script | undefined +): + | { native: ReturnType } + | { "plutus:v1": string } + | { "plutus:v2": string } + | { "plutus:v3": string } + | undefined => { + if (!script) { + return undefined + } + + switch (script._tag) { + case "NativeScript": + return { native: NativeScripts.toJSON(script.script) } + case "PlutusV1": + return { "plutus:v1": Bytes.toHex(script.bytes) } + case "PlutusV2": + return { "plutus:v2": Bytes.toHex(script.bytes) } + case "PlutusV3": + return { "plutus:v3": Bytes.toHex(script.bytes) } + } +} + +const toBlockfrostAdditionalUtxoSet = (additionalUTxOs: Array) => + additionalUTxOs.map((utxo) => { + const txOut: Record = { + address: CoreAddress.toBech32(utxo.address), + value: toBlockfrostValue(utxo.assets), + ...toBlockfrostDatum(utxo.datumOption) + } + + const script = toBlockfrostScript(utxo.scriptRef) + if (script) { + txOut.script = script + } + + return [ + { + txId: TransactionHash.toHex(utxo.transactionId), + index: Number(utxo.index) + }, + txOut + ] + }) + /** * Blockfrost script info response schema */ @@ -107,25 +195,19 @@ const getScriptByHash = return withRateLimit( HttpUtils.get(`${baseUrl}/scripts/${scriptHash}`, BlockfrostScriptInfo, createHeaders(projectId)) ).pipe( - Effect.mapError(wrapError("getScriptByHash")), + Effect.catchAll(wrapError("getScriptByHash")), Effect.flatMap((info) => { - // For native scripts, we could return NativeScript but for now focus on Plutus - if (info.type === "timelock" || info.type === "native") { - return Effect.fail( - new ProviderError({ - message: `Native scripts not yet supported: ${scriptHash}`, - cause: "Native script" - }) - ) - } - // Fetch CBOR for Plutus scripts + // Fetch CBOR for all script types (Blockfrost serves CBOR for native/timelock too) return withRateLimit( HttpUtils.get(`${baseUrl}/scripts/${scriptHash}/cbor`, BlockfrostScriptCbor, createHeaders(projectId)) ).pipe( - Effect.mapError(wrapError("getScriptByHash")), + Effect.catchAll(wrapError("getScriptByHash")), Effect.map((cbor) => { const scriptBytes = Bytes.fromHex(cbor.cbor) switch (info.type) { + case "timelock": + case "native": + return NativeScripts.fromCBORHex(cbor.cbor) case "plutusV1": return new PlutusV1.PlutusV1({ bytes: scriptBytes }) case "plutusV2": @@ -162,7 +244,7 @@ const getDatumByHash = const data = PlutusData.fromCBORHex(datum.cbor) return new InlineDatum.InlineDatum({ data }) }), - Effect.mapError(wrapError("getDatumByHash")) + Effect.catchAll(wrapError("getDatumByHash")) ) } @@ -180,7 +262,7 @@ export const getProtocolParameters = (baseUrl: string, projectId?: string) => `${baseUrl}/epochs/latest/parameters`, Blockfrost.BlockfrostProtocolParameters, createHeaders(projectId) - ).pipe(Effect.map(Blockfrost.transformProtocolParameters), Effect.mapError(wrapError("getProtocolParameters"))) + ).pipe(Effect.map(Blockfrost.transformProtocolParameters), Effect.catchAll(wrapError("getProtocolParameters"))) ) /** @@ -274,7 +356,7 @@ export const getUtxos = { concurrency: 10 } ) ), - Effect.mapError(wrapError("getUtxos")) + Effect.catchAll(wrapError("getUtxos")) ) } @@ -370,7 +452,7 @@ export const getUtxosWithUnit = { concurrency: 10 } ) ), - Effect.mapError(wrapError("getUtxosWithUnit")) + Effect.catchAll(wrapError("getUtxosWithUnit")) ) } @@ -459,7 +541,7 @@ export const getUtxoByUnit = (baseUrl: string, projectId?: string) => (unit: str }) ) }), - Effect.mapError(wrapError("getUtxoByUnit")) + Effect.catchAll(wrapError("getUtxoByUnit")) ) } @@ -526,7 +608,7 @@ export const getUtxosByOutRef = { concurrency: 10 } ) }), - Effect.mapError(wrapError("getUtxosByOutRef")) + Effect.catchAll(wrapError("getUtxosByOutRef")) ) ) @@ -545,7 +627,7 @@ export const getDelegation = (baseUrl: string, projectId?: string) => (rewardAdd Effect.map(Blockfrost.transformDelegation), // Handle 404 - account not registered/never staked Effect.catchIf(is404Error, () => Effect.succeed({ poolId: null, rewards: 0n } as Provider.Delegation)), - Effect.mapError(wrapError("getDelegation")) + Effect.catchAll(wrapError("getDelegation")) ) } @@ -568,7 +650,7 @@ export const getDatum = (baseUrl: string, projectId?: string) => (datumHash: Dat catch: (error) => new ProviderError({ message: "Failed to parse datum CBOR", cause: error }) }) }), - Effect.mapError(wrapError("getDatum")) + Effect.catchAll(wrapError("getDatum")) ) ) } @@ -588,14 +670,14 @@ export const awaitTx = createHeaders(projectId) ).pipe( Effect.map(() => true), - Effect.mapError(wrapError("awaitTx")) + Effect.catchAll(wrapError("awaitTx")) ) ) return Effect.retry(checkTx, Schedule.fixed(`${checkInterval} millis`)).pipe( Effect.timeout(timeout), Effect.catchAllCause( - (cause) => new ProviderError({ cause, message: "Failed to await transaction confirmation" }) + (cause) => Effect.fail(new ProviderError({ cause, message: "Blockfrost awaitTx failed" })) ) ) } @@ -620,7 +702,7 @@ export const submitTx = (baseUrl: string, projectId?: string) => (tx: Transactio catch: (error) => new ProviderError({ message: "Failed to parse transaction hash", cause: error }) }) }), - Effect.mapError(wrapError("submitTx")) + Effect.catchAll(wrapError("submitTx")) ) ) } @@ -644,31 +726,7 @@ export const evaluateTx = // Build additional UTxO set if provided const additionalUtxoSet = additionalUTxOs && additionalUTxOs.length > 0 - ? Ogmios.toOgmiosUTxOs(additionalUTxOs).map((utxo) => { - const txIn = { - txId: utxo.transaction.id, - index: utxo.index - } - - const txOut: Record = { - address: utxo.address, - value: utxo.value - } - - // Add datum if present - if (utxo.datum) { - txOut.datum = utxo.datum - } else if (utxo.datumHash) { - txOut.datumHash = utxo.datumHash - } - - // Add script if present (required for reference script UTxOs) - if (utxo.script) { - txOut.script = utxo.script - } - - return [txIn, txOut] - }) + ? toBlockfrostAdditionalUtxoSet(additionalUTxOs) : [] const payload = { @@ -682,6 +740,6 @@ export const evaluateTx = payload, Blockfrost.JsonwspOgmiosEvaluationResponse, headers - ).pipe(Effect.map(Blockfrost.transformJsonwspOgmiosEvaluationResult), Effect.mapError(wrapError("evaluateTx"))) + ).pipe(Effect.flatMap(Blockfrost.transformJsonwspOgmiosEvaluationResult), Effect.catchAll(wrapError("evaluateTx"))) ) } diff --git a/packages/evolution/src/sdk/provider/internal/KoiosEffect.ts b/packages/evolution/src/sdk/provider/internal/KoiosEffect.ts index 21a51494..2fe81482 100644 --- a/packages/evolution/src/sdk/provider/internal/KoiosEffect.ts +++ b/packages/evolution/src/sdk/provider/internal/KoiosEffect.ts @@ -22,6 +22,17 @@ import * as HttpUtils from "./HttpUtils.js" import * as _Koios from "./Koios.js" import * as _Ogmios from "./Ogmios.js" +/** + * Wrap errors into ProviderError + */ +const wrapError = (operation: string) => (cause: unknown) => + Effect.fail( + new Provider.ProviderError({ + message: `Koios ${operation} failed`, + cause + }) + ) + export const getProtocolParameters = (baseUrl: string, token?: string) => Effect.gen(function* () { const url = `${baseUrl}/epoch_params?limit=1&order=epoch_no.desc` @@ -31,9 +42,7 @@ export const getProtocolParameters = (baseUrl: string, token?: string) => HttpUtils.get(url, schema, bearerToken), // Allows for dependency injection and easier testing Effect.timeout(10_000), - Effect.catchAllCause( - (cause) => new Provider.ProviderError({ cause, message: "Failed to fetch protocol parameters from Koios" }) - ), + Effect.catchAll(wrapError("getProtocolParameters")), Effect.provide(FetchHttpClient.layer) ) @@ -72,9 +81,7 @@ export const getUtxos = return pipe( _Koios.getUtxosEffect(baseUrl, addressStr, token ? { Authorization: `Bearer ${token}` } : undefined), Effect.timeout(10_000), - Effect.catchAllCause( - (cause) => new Provider.ProviderError({ cause, message: "Failed to fetch UTxOs from Koios" }) - ) + Effect.catchAll(wrapError("getUtxos")) ) } @@ -95,9 +102,7 @@ export const getUtxosWithUnit = }) ), Effect.timeout(10_000), - Effect.catchAllCause( - (cause) => new Provider.ProviderError({ cause, message: "Failed to fetch UTxOs with unit from Koios" }) - ) + Effect.catchAll(wrapError("getUtxosWithUnit")) ) } @@ -148,9 +153,7 @@ export const getUtxoByUnit = (baseUrl: string, token?: string) => (unit: string) ) }), Effect.timeout(10_000), - Effect.catchAllCause( - (cause) => new Provider.ProviderError({ cause, message: "Failed to fetch UTxO by unit from Koios" }) - ) + Effect.catchAll(wrapError("getUtxoByUnit")) ) export const getUtxosByOutRef = @@ -168,9 +171,7 @@ export const getUtxosByOutRef = HttpUtils.postJson(url, body, Schema.Array(_Koios.TxInfoSchema), bearerToken), Effect.provide(FetchHttpClient.layer), Effect.timeout(10_000), - Effect.catchAllCause( - (cause) => new Provider.ProviderError({ cause, message: "Failed to fetch UTxOs by OutRef from Koios" }) - ) + Effect.catchAll(wrapError("getUtxosByOutRef")) ) if (result) { @@ -224,9 +225,7 @@ export const getDelegation = (baseUrl: string, token?: string) => (rewardAddress : Effect.succeed(result[0]) ), Effect.timeout(10_000), - Effect.catchAllCause( - (cause) => new Provider.ProviderError({ cause, message: "Failed to fetch delegation from Koios" }) - ) + Effect.catchAll(wrapError("getDelegation")) ) return { @@ -258,9 +257,7 @@ export const getDatum = (baseUrl: string, token?: string) => (datumHash: DatumHa : Effect.succeed(result[0]) ), Effect.timeout(10_000), - Effect.catchAllCause( - (cause) => new Provider.ProviderError({ cause, message: "Failed to fetch datum from Koios" }) - ) + Effect.catchAll(wrapError("getDatum")) ) return Schema.decodeSync(PlutusData.FromCBORHex())(result.bytes) @@ -286,7 +283,8 @@ export const awaitTx = }), Effect.timeout(timeout), Effect.catchAllCause( - (cause) => new Provider.ProviderError({ cause, message: "Failed to await transaction confirmation" }) + (cause) => + Effect.fail(new Provider.ProviderError({ cause, message: "Koios awaitTx failed" })) ), Effect.as(true) ) @@ -304,7 +302,7 @@ export const submitTx = (baseUrl: string, token?: string) => (tx: Transaction.Tr HttpUtils.postUint8Array(url, txCborBytes, _Koios.TxHashSchema, bearerToken), Effect.provide(FetchHttpClient.layer), Effect.timeout(10_000), - Effect.catchAllCause((cause) => new Provider.ProviderError({ cause, message: "Failed to submit transaction" })) + Effect.catchAll(wrapError("submitTx")) ) return Schema.decodeSync(TransactionHash.FromHex)(result) @@ -336,9 +334,7 @@ export const evaluateTx = HttpUtils.postJson(url, body, schema, bearerToken), Effect.provide(FetchHttpClient.layer), Effect.timeout(10_000), - Effect.catchAllCause( - (cause) => new Provider.ProviderError({ cause, message: "Failed to evaluate transaction" }) - ) + Effect.catchAll(wrapError("evaluateTx")) ) const evalRedeemers = result.map((item) => { diff --git a/packages/evolution/src/sdk/provider/internal/KupmiosEffects.ts b/packages/evolution/src/sdk/provider/internal/KupmiosEffects.ts index 0497c759..6f8cf427 100644 --- a/packages/evolution/src/sdk/provider/internal/KupmiosEffects.ts +++ b/packages/evolution/src/sdk/provider/internal/KupmiosEffects.ts @@ -31,6 +31,17 @@ import * as Ogmios from "./Ogmios.js" const TIMEOUT = 10_000 +/** + * Wrap errors into ProviderError + */ +const wrapError = (operation: string) => (cause: unknown) => + Effect.fail( + new Provider.ProviderError({ + message: `Kupmios ${operation} failed`, + cause + }) + ) + // Internal utility functions (not exported) const toProtocolParameters = (result: Ogmios.ProtocolParameters): Provider.ProtocolParameters => { return { @@ -96,7 +107,7 @@ const retrieveDatumEffect = }), Effect.retry(Schedule.compose(Schedule.exponential(50), Schedule.recurs(5))), Effect.timeout(5_000), - Effect.catchAll((cause) => new Provider.ProviderError({ cause, message: "Failed to retrieve datum" })) + Effect.catchAll(wrapError("retrieveDatum")) ) } else if (datum_type === "hash" && datum_hash) { const hashBytes = Bytes.fromHex(datum_hash) @@ -143,7 +154,7 @@ const getScriptEffect = throw new Error(`Unknown script language: ${language}`) } }), - Effect.catchAll((cause) => new Provider.ProviderError({ cause, message: "Failed to get script" })) + Effect.catchAll(wrapError("getScript")) ) } else return undefined }) @@ -192,7 +203,7 @@ export const getProtocolParametersEffect = Effect.fn("getProtocolParameters")(fu const { result } = yield* pipe( HttpUtils.postJson(ogmiosUrl, data, schema, headers?.ogmiosHeader), Effect.timeout(TIMEOUT), - Effect.catchAll((cause) => new Provider.ProviderError({ cause, message: "Failed to get protocol parameters" })), + Effect.catchAll(wrapError("getProtocolParameters")), Effect.provide(FetchHttpClient.layer) ) return toProtocolParameters(result) @@ -214,7 +225,7 @@ export const getUtxosEffect = (kupoUrl: string, headers?: { kupoHeader?: Record< HttpUtils.get(pattern, schema, headers?.kupoHeader), Effect.flatMap((u) => toUtxos(u)), Effect.timeout(TIMEOUT), - Effect.catchAll((cause) => new Provider.ProviderError({ cause, message: "Failed to get UTxOs" })), + Effect.catchAll(wrapError("getUtxos")), Effect.provide(FetchHttpClient.layer) ) return utxos @@ -234,7 +245,7 @@ export const getUtxoByUnitEffect = (kupoUrl: string, headers?: { kupoHeader?: Re HttpUtils.get(pattern, schema, headers?.kupoHeader), Effect.flatMap((u) => toUtxos(u)), Effect.timeout(TIMEOUT), - Effect.catchAll((cause) => new Provider.ProviderError({ cause, message: "Failed to get UTxO by unit" })), + Effect.catchAll(wrapError("getUtxoByUnit")), Effect.provide(FetchHttpClient.layer) ) @@ -270,7 +281,7 @@ export const getUtxosByOutRefEffect = (kupoUrl: string, headers?: { kupoHeader?: HttpUtils.get(mkPattern(txHash), schema, headers?.kupoHeader), Effect.flatMap((u) => toUtxos(u)), Effect.timeout(TIMEOUT), - Effect.catchAll((cause) => new Provider.ProviderError({ cause, message: "Failed to get UTxOs by OutRef" })) + Effect.catchAll(wrapError("getUtxosByOutRef")) ) ) const utxos: Array> = yield* pipe(program, Effect.provide(FetchHttpClient.layer)) @@ -321,8 +332,8 @@ export const submitTxEffect = (ogmiosUrl: string, headers?: { ogmiosHeader?: Rec ? cause.message : typeof cause === "object" && cause !== null && "description" in cause ? String((cause as { description: unknown }).description) - : "Failed to submit transaction" - return Effect.fail(new Provider.ProviderError({ cause, message: errorMessage })) + : "Kupmios submitTx failed" + return Effect.fail(new Provider.ProviderError({ cause, message: `Kupmios submitTx failed: ${errorMessage}` })) }), Effect.provide(FetchHttpClient.layer) ) @@ -349,7 +360,7 @@ export const getUtxosWithUnitEffect = (kupoUrl: string, headers?: { kupoHeader?: HttpUtils.get(pattern, schema, headers?.kupoHeader), Effect.flatMap((u) => toUtxos(u)), Effect.timeout(TIMEOUT), - Effect.catchAll((cause) => new Provider.ProviderError({ cause, message: "Failed to get UTxOs with unit" })), + Effect.catchAll(wrapError("getUtxosWithUnit")), Effect.provide(FetchHttpClient.layer) ) return utxos @@ -377,7 +388,7 @@ export const evaluateTxEffect = (ogmiosUrl: string, headers?: { ogmiosHeader?: R HttpUtils.postJson(ogmiosUrl, data, schema, headers?.ogmiosHeader), Effect.provide(FetchHttpClient.layer), Effect.timeout(TIMEOUT), - Effect.catchAll((cause) => new Provider.ProviderError({ cause, message: "Failed to evaluate transaction" })) + Effect.catchAll(wrapError("evaluateTx")) ) const evalRedeemers: Array = (result as Array).map((item: any) => { @@ -417,7 +428,9 @@ export const awaitTxEffect = (kupoUrl: string, headers?: { kupoHeader?: Record result.length > 0 }), Effect.timeout(timeout), - Effect.catchAll((cause) => new Provider.ProviderError({ cause, message: "Failed to await transaction" })), + Effect.catchAllCause( + (cause) => Effect.fail(new Provider.ProviderError({ cause, message: "Kupmios awaitTx failed" })) + ), Effect.as(true) ) return result @@ -436,14 +449,14 @@ export const getDelegationEffect = (ogmiosUrl: string, headers?: { ogmiosHeader? HttpUtils.postJson(ogmiosUrl, data, schema, headers?.ogmiosHeader), Effect.provide(FetchHttpClient.layer), Effect.timeout(TIMEOUT), - Effect.catchAll((cause) => new Provider.ProviderError({ cause, message: "Failed to get delegation" })) + Effect.catchAll(wrapError("getDelegation")) ) const delegation = result?.[0] ?? null return { poolId: delegation?.stakePool?.id ? yield* Schema.decode(PoolKeyHash.FromBech32)(delegation.stakePool.id).pipe( - Effect.mapError((cause) => new Provider.ProviderError({ cause, message: "Failed to decode pool key hash" })) + Effect.mapError((cause) => new Provider.ProviderError({ cause, message: "Kupmios getDelegation failed" })) ) : null, rewards: BigInt(delegation?.rewards?.ada?.lovelace ?? 0) @@ -460,7 +473,7 @@ export const getDatumEffect = (kupoUrl: string, headers?: { kupoHeader?: Record< Effect.provide(FetchHttpClient.layer), Effect.timeout(TIMEOUT), Effect.flatMap(Effect.fromNullable), - Effect.catchAll((cause) => new Provider.ProviderError({ cause, message: "Failed to get datum" })) + Effect.catchAll(wrapError("getDatum")) ) return Schema.decodeSync(PlutusData.FromCBORHex())(result.datum) }) diff --git a/packages/evolution/src/sdk/provider/internal/Maestro.ts b/packages/evolution/src/sdk/provider/internal/Maestro.ts index 3e25e932..e4fa6450 100644 --- a/packages/evolution/src/sdk/provider/internal/Maestro.ts +++ b/packages/evolution/src/sdk/provider/internal/Maestro.ts @@ -7,7 +7,18 @@ import { Schema } from "effect" import * as CoreAddress from "../../../Address.js" import * as CoreAssets from "../../../Assets/index.js" +import * as Bytes from "../../../Bytes.js" +import * as PlutusData from "../../../Data.js" +import * as DatumHash from "../../../DatumHash.js" +import type { DatumOption } from "../../../DatumOption.js" +import * as InlineDatum from "../../../InlineDatum.js" +import * as NativeScripts from "../../../NativeScripts.js" +import * as PlutusV1 from "../../../PlutusV1.js" +import * as PlutusV2 from "../../../PlutusV2.js" +import * as PlutusV3 from "../../../PlutusV3.js" import * as PoolKeyHash from "../../../PoolKeyHash.js" +import * as Redeemer from "../../../Redeemer.js" +import type { Script } from "../../../Script.js" import * as TransactionHash from "../../../TransactionHash.js" import * as CoreUTxO from "../../../UTxO.js" import type { EvalRedeemer } from "../../EvalRedeemer.js" @@ -17,40 +28,45 @@ import type * as Provider from "../Provider.js" // Maestro API Response Schemas // ============================================================================ +/** + * Accept both string and number for fields Maestro may return as either type + */ +const StringOrNumber = Schema.Union(Schema.String, Schema.Number) + /** * Maestro protocol parameters response schema */ export const MaestroProtocolParameters = Schema.Struct({ - min_fee_coefficient: Schema.String, + min_fee_coefficient: StringOrNumber, min_fee_constant: Schema.Struct({ ada: Schema.Struct({ - lovelace: Schema.String + lovelace: StringOrNumber }) }), max_transaction_size: Schema.Struct({ - bytes: Schema.String + bytes: StringOrNumber }), max_value_size: Schema.Struct({ - bytes: Schema.String + bytes: StringOrNumber }), stake_credential_deposit: Schema.Struct({ ada: Schema.Struct({ - lovelace: Schema.String + lovelace: StringOrNumber }) }), stake_pool_deposit: Schema.Struct({ ada: Schema.Struct({ - lovelace: Schema.String + lovelace: StringOrNumber }) }), delegate_representative_deposit: Schema.Struct({ ada: Schema.Struct({ - lovelace: Schema.String + lovelace: StringOrNumber }) }), governance_action_deposit: Schema.Struct({ ada: Schema.Struct({ - lovelace: Schema.String + lovelace: StringOrNumber }) }), script_execution_prices: Schema.Struct({ @@ -58,14 +74,14 @@ export const MaestroProtocolParameters = Schema.Struct({ cpu: Schema.String // rational format "numerator/denominator" }), max_execution_units_per_transaction: Schema.Struct({ - memory: Schema.String, - cpu: Schema.String + memory: StringOrNumber, + cpu: StringOrNumber }), - min_utxo_deposit_coefficient: Schema.String, - collateral_percentage: Schema.String, - max_collateral_inputs: Schema.String, + min_utxo_deposit_coefficient: StringOrNumber, + collateral_percentage: StringOrNumber, + max_collateral_inputs: StringOrNumber, min_fee_reference_scripts: Schema.Struct({ - base: Schema.String + base: StringOrNumber }), plutus_cost_models: Schema.Struct({ plutus_v1: Schema.Array(Schema.Number), @@ -102,6 +118,16 @@ export const MaestroScript = Schema.Struct({ json: Schema.NullOr(Schema.Unknown) }) +/** + * Maestro asset UTxO reference schema (simplified response from /assets/{unit}/utxos) + */ +export const MaestroAssetUTxORef = Schema.Struct({ + tx_hash: Schema.String, + index: Schema.Number, + address: Schema.String, + amount: Schema.String +}) + /** * Maestro UTxO schema */ @@ -119,7 +145,14 @@ export const MaestroUTxO = Schema.Struct({ */ export const MaestroDelegation = Schema.Struct({ delegated_pool: Schema.NullOr(Schema.String), - rewards_available: Schema.String + rewards_available: StringOrNumber +}) + +/** + * Maestro transaction response schema (subset needed for output resolution) + */ +export const MaestroTransaction = Schema.Struct({ + outputs: Schema.Array(MaestroUTxO) }) /** @@ -149,10 +182,16 @@ export const MaestroPaginatedResponse = (dataSchema: Schema.Schema) => }) }) -/** - * Maestro evaluation result schema - simplified for now - */ -export const MaestroEvalResult = Schema.Array(Schema.Unknown) +export const MaestroEvaluateRedeemer = Schema.Struct({ + redeemer_tag: Schema.Literal("spend", "mint", "cert", "wdrl", "vote", "propose"), + redeemer_index: Schema.Number, + ex_units: Schema.Struct({ + mem: StringOrNumber, + steps: StringOrNumber + }) +}) + +export const MaestroEvalResult = Schema.Array(MaestroEvaluateRedeemer) // ============================================================================ // Transformation Utilities @@ -173,6 +212,9 @@ export const parseDecimalFromRational = (rationalStr: string): number => { return numerator / denominator } +const toInt = (v: string | number): number => (typeof v === "number" ? v : parseInt(v)) +const toBigInt = (v: string | number): bigint => BigInt(v) + /** * Transform Maestro protocol parameters to Evolution SDK format */ @@ -180,22 +222,22 @@ export const transformProtocolParameters = ( maestroParams: Schema.Schema.Type ): Provider.ProtocolParameters => { return { - minFeeA: parseInt(maestroParams.min_fee_coefficient), - minFeeB: parseInt(maestroParams.min_fee_constant.ada.lovelace), - maxTxSize: parseInt(maestroParams.max_transaction_size.bytes), - maxValSize: parseInt(maestroParams.max_value_size.bytes), - keyDeposit: BigInt(maestroParams.stake_credential_deposit.ada.lovelace), - poolDeposit: BigInt(maestroParams.stake_pool_deposit.ada.lovelace), - drepDeposit: BigInt(maestroParams.delegate_representative_deposit.ada.lovelace), - govActionDeposit: BigInt(maestroParams.governance_action_deposit.ada.lovelace), + minFeeA: toInt(maestroParams.min_fee_coefficient), + minFeeB: toInt(maestroParams.min_fee_constant.ada.lovelace), + maxTxSize: toInt(maestroParams.max_transaction_size.bytes), + maxValSize: toInt(maestroParams.max_value_size.bytes), + keyDeposit: toBigInt(maestroParams.stake_credential_deposit.ada.lovelace), + poolDeposit: toBigInt(maestroParams.stake_pool_deposit.ada.lovelace), + drepDeposit: toBigInt(maestroParams.delegate_representative_deposit.ada.lovelace), + govActionDeposit: toBigInt(maestroParams.governance_action_deposit.ada.lovelace), priceMem: parseDecimalFromRational(maestroParams.script_execution_prices.memory), priceStep: parseDecimalFromRational(maestroParams.script_execution_prices.cpu), - maxTxExMem: BigInt(maestroParams.max_execution_units_per_transaction.memory), - maxTxExSteps: BigInt(maestroParams.max_execution_units_per_transaction.cpu), - coinsPerUtxoByte: BigInt(maestroParams.min_utxo_deposit_coefficient), - collateralPercentage: parseInt(maestroParams.collateral_percentage), - maxCollateralInputs: parseInt(maestroParams.max_collateral_inputs), - minFeeRefScriptCostPerByte: parseInt(maestroParams.min_fee_reference_scripts.base), + maxTxExMem: toBigInt(maestroParams.max_execution_units_per_transaction.memory), + maxTxExSteps: toBigInt(maestroParams.max_execution_units_per_transaction.cpu), + coinsPerUtxoByte: toBigInt(maestroParams.min_utxo_deposit_coefficient), + collateralPercentage: toInt(maestroParams.collateral_percentage), + maxCollateralInputs: toInt(maestroParams.max_collateral_inputs), + minFeeRefScriptCostPerByte: toInt(maestroParams.min_fee_reference_scripts.base), costModels: { PlutusV1: Object.fromEntries( maestroParams.plutus_cost_models.plutus_v1.map((value: number, index: number) => [index.toString(), value]) @@ -212,19 +254,15 @@ export const transformProtocolParameters = ( /** * Transform Maestro datum option to Evolution SDK format - * TODO: Convert to Core datum type when available */ export const transformDatumOption = ( - _maestroDatum?: Schema.Schema.Type | null -): undefined => { - // TODO: Handle datum when Core types support it - // if (!maestroDatum) return undefined - // if (maestroDatum.type === "inline" && maestroDatum.bytes) { - // return Datum.makeInlineDatum(maestroDatum.bytes) - // } else if (maestroDatum.type === "hash") { - // return Datum.makeDatumHash(maestroDatum.hash) - // } - return undefined + maestroDatum?: Schema.Schema.Type | null +): DatumOption | undefined => { + if (!maestroDatum) return undefined + if (maestroDatum.type === "inline" && maestroDatum.bytes) { + return new InlineDatum.InlineDatum({ data: PlutusData.fromCBORHex(maestroDatum.bytes) }) + } + return DatumHash.fromHex(maestroDatum.hash) } /** @@ -260,11 +298,22 @@ export const transformAssets = ( /** * Transform Maestro script reference to Evolution SDK format - * TODO: Convert to Core script type when available */ -export const transformScriptRef = (_maestroScript?: Schema.Schema.Type | null) => { - // TODO: Handle script ref when Core types support it - return undefined +export const transformScriptRef = ( + maestroScript?: Schema.Schema.Type | null +): Script | undefined => { + if (!maestroScript?.bytes) return undefined + const scriptBytes = Bytes.fromHex(maestroScript.bytes) + switch (maestroScript.type) { + case "plutusv1": + return new PlutusV1.PlutusV1({ bytes: scriptBytes }) + case "plutusv2": + return new PlutusV2.PlutusV2({ bytes: scriptBytes }) + case "plutusv3": + return new PlutusV3.PlutusV3({ bytes: scriptBytes }) + case "native": + return NativeScripts.fromCBORHex(maestroScript.bytes) + } } /** @@ -274,16 +323,16 @@ export const transformUTxO = (maestroUtxo: Schema.Schema.Type { return { poolId: maestroDelegation.delegated_pool - ? Schema.decodeSync(PoolKeyHash.FromHex)(maestroDelegation.delegated_pool) + ? PoolKeyHash.fromBech32(maestroDelegation.delegated_pool) : null, rewards: BigInt(maestroDelegation.rewards_available) } @@ -307,8 +356,12 @@ export const transformDelegation = ( export const transformEvaluationResult = ( maestroResult: Schema.Schema.Type ): Array => { - // For now, return as-is since we don't have the exact Maestro eval format - // This will need to be updated based on actual Maestro evaluation response - // Note: May need to convert mem/steps to bigint when Maestro format is known - return maestroResult as Array + return maestroResult.map((redeemer) => ({ + redeemer_tag: (redeemer.redeemer_tag === "wdrl" ? "reward" : redeemer.redeemer_tag) as Redeemer.RedeemerTag, + redeemer_index: redeemer.redeemer_index, + ex_units: new Redeemer.ExUnits({ + mem: BigInt(redeemer.ex_units.mem), + steps: BigInt(redeemer.ex_units.steps) + }) + })) } diff --git a/packages/evolution/src/sdk/provider/internal/MaestroEffect.ts b/packages/evolution/src/sdk/provider/internal/MaestroEffect.ts index 331369da..1f0d2bbf 100644 --- a/packages/evolution/src/sdk/provider/internal/MaestroEffect.ts +++ b/packages/evolution/src/sdk/provider/internal/MaestroEffect.ts @@ -10,15 +10,16 @@ import * as Bytes from "../../../Bytes.js" import type * as Credential from "../../../Credential.js" import * as PlutusData from "../../../Data.js" import type * as DatumHash from "../../../DatumHash.js" +import * as Script from "../../../Script.js" +import * as ScriptRef from "../../../ScriptRef.js" import * as Transaction from "../../../Transaction.js" import * as TransactionHash from "../../../TransactionHash.js" import type * as TransactionInput from "../../../TransactionInput.js" +import * as TxOut from "../../../TxOut.js" import type * as CoreUTxO from "../../../UTxO.js" -import type { EvalRedeemer } from "../../EvalRedeemer.js" import { ProviderError } from "../Provider.js" import * as HttpUtils from "./HttpUtils.js" import * as Maestro from "./Maestro.js" -import * as Ogmios from "./Ogmios.js" // ============================================================================ // Helper Functions @@ -43,13 +44,15 @@ const createHeadersWithAmounts = (apiKey: string): Record => ({ }) /** - * Wrap HTTP errors into ProviderError following Kupmios pattern + * Wrap errors into ProviderError */ -const wrapError = (operation: string) => (error: unknown) => - new ProviderError({ - message: `Failed to ${operation}`, - cause: error - }) +const wrapError = (operation: string) => (cause: unknown) => + Effect.fail( + new ProviderError({ + message: `Maestro ${operation} failed`, + cause + }) + ) // ============================================================================ // Configuration @@ -65,8 +68,12 @@ const TIMEOUT = 10_000 // 10 seconds timeout for requests * Get protocol parameters from Maestro */ export const getProtocolParameters = (baseUrl: string, apiKey: string) => - HttpUtils.get(`${baseUrl}/protocol-parameters`, Maestro.MaestroProtocolParameters, createHeaders(apiKey)).pipe( - Effect.map(Maestro.transformProtocolParameters), + HttpUtils.get( + `${baseUrl}/protocol-parameters`, + Maestro.MaestroTimestampedResponse(Maestro.MaestroProtocolParameters), + createHeaders(apiKey) + ).pipe( + Effect.map((response) => Maestro.transformProtocolParameters(response.data)), Effect.timeout(TIMEOUT), Effect.catchAll(wrapError("get protocol parameters")) ) @@ -81,11 +88,15 @@ export const getProtocolParameters = (baseUrl: string, apiKey: string) => export const getUtxos = (baseUrl: string, apiKey: string) => (addressOrCredential: CoreAddress.Address | Credential.Credential) => Effect.gen(function* () { - // Extract address string from Address or Credential - const addressStr = - addressOrCredential instanceof CoreAddress.Address - ? CoreAddress.toBech32(addressOrCredential) - : addressOrCredential.hash // Use credential hash directly + if (!(addressOrCredential instanceof CoreAddress.Address)) { + return yield* Effect.fail( + new ProviderError({ + message: "Maestro provider does not support credential-based UTxO queries. Pass a full Address instead.", + cause: "Unsupported operation" + }) + ) + } + const addressStr = CoreAddress.toBech32(addressOrCredential) // Get all pages of UTxOs const allUtxos = yield* getUtxosWithPagination(`${baseUrl}/addresses/${addressStr}/utxos`, apiKey) @@ -100,22 +111,23 @@ export const getUtxosWithUnit = (baseUrl: string, apiKey: string) => (addressOrCredential: CoreAddress.Address | Credential.Credential, unit: string) => Effect.gen(function* () { - // For Maestro, we get UTxOs by unit and then filter by address if needed - // This is different from address-first approach but matches the API design - const allUtxos = yield* getUtxosWithPagination(`${baseUrl}/assets/${unit}/utxos`, apiKey) - - // Transform UTxOs first - const transformedUtxos = allUtxos.map(Maestro.transformUTxO) - - // Filter by address if addressOrCredential is provided - const addressStr = - addressOrCredential instanceof CoreAddress.Address - ? CoreAddress.toBech32(addressOrCredential) - : addressOrCredential.hash - - // Filter UTxOs that belong to the specified address/credential - // Use CoreAddress.toBech32 to convert Core Address to string for comparison - return transformedUtxos.filter((utxo) => CoreAddress.toBech32(utxo.address) === addressStr) + // Use address endpoint and filter by unit client-side, + // because /assets/{unit}/utxos returns a simplified response without full UTxO details + if (!(addressOrCredential instanceof CoreAddress.Address)) { + return yield* Effect.fail( + new ProviderError({ + message: "Maestro provider does not support credential-based UTxO queries. Pass a full Address instead.", + cause: "Unsupported operation" + }) + ) + } + const addressStr = CoreAddress.toBech32(addressOrCredential) + + const allUtxos = yield* getUtxosWithPagination(`${baseUrl}/addresses/${addressStr}/utxos`, apiKey) + + // Filter raw Maestro UTxOs for unit match before transforming + const matching = allUtxos.filter((u) => u.assets.some((a) => a.unit === unit)) + return matching.map(Maestro.transformUTxO) }) /** @@ -124,19 +136,31 @@ export const getUtxosWithUnit = export const getUtxosByOutRef = (baseUrl: string, apiKey: string) => (inputs: ReadonlyArray) => Effect.gen(function* () { - // Maestro supports batch UTxO resolution via POST with output references - const outputReferences = Array.from(inputs).map( - (input) => `${TransactionHash.toHex(input.transactionId)}#${Number(input.index)}` - ) + // Group by tx_hash to minimize API calls + const byTxHash = new Map>() + for (const input of inputs) { + const hash = TransactionHash.toHex(input.transactionId) + const indices = byTxHash.get(hash) ?? [] + indices.push(Number(input.index)) + byTxHash.set(hash, indices) + } - const response = yield* HttpUtils.postJson( - `${baseUrl}/utxos/batch`, - { output_references: outputReferences }, - Schema.Array(Maestro.MaestroUTxO), - createHeadersWithAmounts(apiKey) - ).pipe(Effect.timeout(TIMEOUT), Effect.catchAll(wrapError("get UTxOs by outRef"))) + const results: Array> = [] + + for (const [txHash, indices] of byTxHash) { + const tx = yield* HttpUtils.get( + `${baseUrl}/transactions/${txHash}`, + Maestro.MaestroTimestampedResponse(Maestro.MaestroTransaction), + createHeadersWithAmounts(apiKey) + ).pipe(Effect.timeout(TIMEOUT), Effect.catchAll(wrapError("get UTxOs by outRef"))) - return response.map(Maestro.transformUTxO) + for (const idx of indices) { + const output = tx.data.outputs.find((o) => o.index === idx) + if (output) results.push(output) + } + } + + return results.map(Maestro.transformUTxO) }) // ============================================================================ @@ -147,8 +171,12 @@ export const getUtxosByOutRef = * Get delegation info for a credential */ export const getDelegation = (baseUrl: string, apiKey: string) => (rewardAddress: string) => - HttpUtils.get(`${baseUrl}/accounts/${rewardAddress}`, Maestro.MaestroDelegation, createHeaders(apiKey)).pipe( - Effect.map(Maestro.transformDelegation), + HttpUtils.get( + `${baseUrl}/accounts/${rewardAddress}`, + Maestro.MaestroTimestampedResponse(Maestro.MaestroDelegation), + createHeaders(apiKey) + ).pipe( + Effect.map((response) => Maestro.transformDelegation(response.data)), Effect.timeout(TIMEOUT), Effect.catchAll(wrapError("get delegation")) ) @@ -188,28 +216,36 @@ export const evaluateTx = (baseUrl: string, apiKey: string) => (tx: Transaction.Transaction, additionalUTxOs?: Array) => Effect.gen(function* () { const txCborHex = Transaction.toCBORHex(tx) - // Use Ogmios format for additional UTxOs - const ogmiosUtxos = additionalUTxOs ? Ogmios.toOgmiosUTxOs(additionalUTxOs) : undefined + const additionalUtxos = additionalUTxOs?.map((utxo) => { + const txOut = new TxOut.TransactionOutput({ + address: utxo.address, + assets: utxo.assets, + datumOption: utxo.datumOption, + scriptRef: utxo.scriptRef + ? new ScriptRef.ScriptRef({ bytes: Bytes.fromHex(Script.toCBORHex(utxo.scriptRef)) }) + : undefined + }) + + return { + tx_hash: TransactionHash.toHex(utxo.transactionId), + index: Number(utxo.index), + txout_cbor: TxOut.toCBORHex(txOut) + } + }) const requestBody = { - transaction: txCborHex, - ...(ogmiosUtxos && { - additional_utxo_set: ogmiosUtxos.map((utxo) => ({ - txHash: utxo.transaction.id, - outputIndex: utxo.index - })) - }) + cbor: txCborHex, + ...(additionalUtxos && additionalUtxos.length > 0 ? { additional_utxos: additionalUtxos } : {}) } const response = yield* HttpUtils.postJson( - `${baseUrl}/evaluate`, + `${baseUrl}/transactions/evaluate`, requestBody, - Schema.Array(Schema.Any), // Will need proper evaluation response schema + Maestro.MaestroEvalResult, createHeaders(apiKey) ).pipe(Effect.timeout(TIMEOUT), Effect.catchAll(wrapError("evaluate transaction"))) - // Transform response to match Evolution SDK format - return response as Array + return Maestro.transformEvaluationResult(response) }) /** @@ -217,14 +253,14 @@ export const evaluateTx = */ export const getUtxoByUnit = (baseUrl: string, apiKey: string) => (unit: string) => Effect.gen(function* () { - // Get first UTxO containing this unit - const utxos = yield* getUtxosWithPagination( - `${baseUrl}/assets/${unit}/utxos`, - apiKey, - 1 // Just get the first one + // Get the first UTxO reference from the asset endpoint (simplified response) + const refs = yield* HttpUtils.get( + `${baseUrl}/assets/${unit}/utxos?count=1`, + Maestro.MaestroPaginatedResponse(Maestro.MaestroAssetUTxORef), + createHeadersWithAmounts(apiKey) ).pipe(Effect.timeout(TIMEOUT), Effect.catchAll(wrapError("get UTxO by unit"))) - if (utxos.length === 0) { + if (refs.data.length === 0) { return yield* Effect.fail( new ProviderError({ cause: new Error("No UTxO found for unit"), @@ -233,7 +269,23 @@ export const getUtxoByUnit = (baseUrl: string, apiKey: string) => (unit: string) ) } - return Maestro.transformUTxO(utxos[0]) + const ref = refs.data[0] + + // Resolve the full UTxO via the address endpoint and filter by tx_hash + index + const allUtxos = yield* getUtxosWithPagination(`${baseUrl}/addresses/${ref.address}/utxos`, apiKey) + + const match = allUtxos.find((u) => u.tx_hash === ref.tx_hash && u.index === ref.index) + + if (!match) { + return yield* Effect.fail( + new ProviderError({ + cause: new Error("No UTxO found for unit"), + message: "UTxO not found" + }) + ) + } + + return Maestro.transformUTxO(match) }) /** @@ -244,16 +296,18 @@ export const getDatum = (baseUrl: string, apiKey: string) => (datumHash: DatumHa const datumHashHex = Bytes.toHex(datumHash.hash) const response = yield* HttpUtils.get( `${baseUrl}/datums/${datumHashHex}`, - Schema.Struct({ - bytes: Schema.String - }), + Maestro.MaestroTimestampedResponse( + Schema.Struct({ + bytes: Schema.String + }) + ), { "api-key": apiKey, accept: "application/json" } ).pipe(Effect.timeout(TIMEOUT), Effect.catchAll(wrapError("get datum"))) - return Schema.decodeSync(PlutusData.FromCBORHex())(response.bytes) + return Schema.decodeSync(PlutusData.FromCBORHex())(response.data.bytes) }) /** @@ -270,20 +324,17 @@ export const awaitTx = // Check if transaction exists and is confirmed const result = yield* HttpUtils.get( `${baseUrl}/transactions/${txHashHex}`, - Schema.Struct({ - hash: Schema.String, - block: Schema.optional( - Schema.Struct({ - hash: Schema.String, - slot: Schema.Number - }) - ) - }), + Maestro.MaestroTimestampedResponse( + Schema.Struct({ + tx_hash: Schema.String, + block_hash: Schema.String + }) + ), createHeaders(apiKey) - ).pipe(Effect.timeout(TIMEOUT), Effect.catchAll(wrapError("await transaction")), Effect.either) + ).pipe(Effect.timeout(TIMEOUT), Effect.catchAll(wrapError("awaitTx")), Effect.either) - // If successful and we have a block, transaction is confirmed - if (result._tag === "Right" && result.right.block) { + // If successful and we have a block_hash, transaction is confirmed + if (result._tag === "Right" && result.right.data.block_hash) { return true } @@ -291,7 +342,7 @@ export const awaitTx = yield* Effect.sleep(`${interval} millis`) } }).pipe(Effect.timeout(timeout), Effect.catchAllCause( - (cause) => new ProviderError({ cause, message: "Failed to await transaction confirmation" }) + (cause) => Effect.fail(new ProviderError({ cause, message: "Maestro awaitTx failed" })) )) } diff --git a/packages/evolution/test/provider/conformance.ts b/packages/evolution/test/provider/conformance.ts index 0fde42ab..b2bbd93a 100644 --- a/packages/evolution/test/provider/conformance.ts +++ b/packages/evolution/test/provider/conformance.ts @@ -4,7 +4,8 @@ import * as Address from "../../src/Address.js" import * as Assets from "../../src/Assets/index.js" import * as AssetsUnit from "../../src/Assets/Unit.js" import * as PoolKeyHash from "../../src/PoolKeyHash.js" -import { type Provider,ProviderError } from "../../src/sdk/provider/Provider.js" +import { type Provider } from "../../src/sdk/provider/Provider.js" +import * as Transaction from "../../src/Transaction.js" import * as TransactionHash from "../../src/TransactionHash.js" import { PREPROD_SCRIPT_ADDRESS_BECH32, @@ -17,6 +18,7 @@ import { preprodTxHash, previewTxHash, } from "./fixtures/constants.js" +import { evalSample1, evalSample2, evalSample3, evalSample4 } from "./fixtures/evaluateTx.js" /** * Registers conformance `it()` tests for the Provider interface. @@ -102,10 +104,35 @@ export function registerConformanceTests(factory: () => Provider) { }) it("awaitTx rejects for preview-only tx on preprod", { timeout: 10_000 }, async () => { - await expect(provider.awaitTx(previewTxHash(), 1000, 5000)).rejects.toThrow(ProviderError) + await expect(provider.awaitTx(previewTxHash(), 1000, 5000)).rejects.toThrow( + "awaitTx failed" + ) }) // submitTx and evaluateTx require a valid signed CBOR tx — skipped until we have tx fixtures it.skip("submitTx", async () => {}) - it.skip("evaluateTx", async () => {}) + + it("evaluateTx with multiple spend redeemers", async () => { + const tx = Transaction.fromCBORHex(evalSample1.transaction) + const result = await provider.evaluateTx(tx, evalSample1.utxos) + expect(result).toEqual(evalSample1.redeemersExUnits) + }) + + it("evaluateTx with PlutusV2 reference script", async () => { + const tx = Transaction.fromCBORHex(evalSample2.transaction) + const result = await provider.evaluateTx(tx, evalSample2.utxos) + expect(result).toEqual(evalSample2.redeemersExUnits) + }) + + it("evaluateTx with spend, mint, and reward redeemers", async () => { + const tx = Transaction.fromCBORHex(evalSample3.transaction) + const result = await provider.evaluateTx(tx, evalSample3.utxos) + expect(result).toEqual(evalSample3.redeemersExUnits) + }) + + it("evaluateTx with cert redeemer (PlutusV3)", async () => { + const tx = Transaction.fromCBORHex(evalSample4.transaction) + const result = await provider.evaluateTx(tx, evalSample4.utxos) + expect(result).toEqual(evalSample4.redeemersExUnits) + }) } diff --git a/packages/evolution/test/provider/fixtures/evaluateTx.ts b/packages/evolution/test/provider/fixtures/evaluateTx.ts new file mode 100644 index 00000000..d0e821d9 --- /dev/null +++ b/packages/evolution/test/provider/fixtures/evaluateTx.ts @@ -0,0 +1,294 @@ +import * as Address from "../../../src/Address.js" +import * as Assets from "../../../src/Assets/index.js" +import * as Bytes from "../../../src/Bytes.js" +import * as Data from "../../../src/Data.js" +import * as InlineDatum from "../../../src/InlineDatum.js" +import * as PlutusV2 from "../../../src/PlutusV2.js" +import * as PlutusV3 from "../../../src/PlutusV3.js" +import * as Redeemer from "../../../src/Redeemer.js" +import * as TransactionHash from "../../../src/TransactionHash.js" +import * as UTxO from "../../../src/UTxO.js" + +const EVAL_SAMPLE_1_ADDRESS = Address.fromBech32( + "addr_test1wrqlusc0rxkzfz5206j8mvgxqqkyxfl9gtplm3s26eypzqcxsnfs3" +) +const EVAL_SAMPLE_1_DATUM = new InlineDatum.InlineDatum({ + data: Data.fromCBORHex( + "d87981581c9fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e50" + ), +}) + +export const evalSample1 = { + utxos: [ + new UTxO.UTxO({ + transactionId: TransactionHash.fromHex( + "35509191d07f018849fa7d32217b70ae33b49983aea21339850d6fcda31b030b" + ), + index: 0n, + address: EVAL_SAMPLE_1_ADDRESS, + assets: Assets.fromLovelace(10_000_000n), + datumOption: EVAL_SAMPLE_1_DATUM, + }), + new UTxO.UTxO({ + transactionId: TransactionHash.fromHex( + "75af72128f59d7cae87965399a01fd775fb8f69095cecb5ce45f55b8e3f5052c" + ), + index: 0n, + address: EVAL_SAMPLE_1_ADDRESS, + assets: Assets.fromLovelace(10_000_000n), + datumOption: EVAL_SAMPLE_1_DATUM, + }), + new UTxO.UTxO({ + transactionId: TransactionHash.fromHex( + "4f070d5ffaa972c554bdbbad5d01ddd032fddf91f8f3262136b8cce0ba3b790a" + ), + index: 0n, + address: EVAL_SAMPLE_1_ADDRESS, + assets: Assets.fromLovelace(10_000_000n), + datumOption: EVAL_SAMPLE_1_DATUM, + }), + new UTxO.UTxO({ + transactionId: TransactionHash.fromHex( + "f4918fe2de471b137901d6809e849ee920ed9013f7454fd073bd5b632b9596f0" + ), + index: 0n, + address: EVAL_SAMPLE_1_ADDRESS, + assets: Assets.fromLovelace(10_000_000n), + datumOption: EVAL_SAMPLE_1_DATUM, + }), + ], + transaction: + "84a8008482582035509191d07f018849fa7d32217b70ae33b49983aea21339850d6fcda31b030b008258204f070d5ffaa972c554bdbbad5d01ddd032fddf91f8f3262136b8cce0ba3b790a0082582075af72128f59d7cae87965399a01fd775fb8f69095cecb5ce45f55b8e3f5052c00825820f4918fe2de471b137901d6809e849ee920ed9013f7454fd073bd5b632b9596f0000181825839009fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e505064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d1a025f365c021a000323a40b58203f42956d83a3940b571b4cf51c6098535b9c7e0b240bf4daaa0fb1c917e8a4370d81825820f4918fe2de471b137901d6809e849ee920ed9013f7454fd073bd5b632b9596f0010e81581c9fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e5010825839009fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e505064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420d821b000000022ca6f211a2581c22691d3d969ecf5802226290c2fb98e2bc08522d5b726c1f5f400105a1445465737403581cef6ed47a6917a3cbbeb46561e8853da969343794d66128598a34af2ca14e4275726e61626c65546f6b656e3201111a004c4b40a20584840000d879814d48656c6c6f2c20576f726c6421821966ad1a0077ca99840001d879814d48656c6c6f2c20576f726c6421821966ad1a0077ca99840002d879814d48656c6c6f2c20576f726c6421821966ad1a0077ca99840003d879814d48656c6c6f2c20576f726c6421821966ad1a0077ca99068158eb58e901000032323232323223223225333006323253330083371e6eb8c008c028dd5002a4410d48656c6c6f2c20576f726c642100100114a06644646600200200644a66601c00229404c94ccc030cdc79bae301000200414a226600600600260200026eb0c02cc030c030c030c030c030c030c030c030c024dd5180098049baa002375c600260126ea80188c02c0045261365653330043370e900018029baa001132325333009300b002149858dd7180480098031baa0011653330023370e900018019baa0011323253330073009002149858dd7180380098021baa001165734aae7555cf2ab9f5742ae881f5f6", + + redeemersExUnits: [ + { + redeemer_tag: "spend" as const, + redeemer_index: 0, + ex_units: new Redeemer.ExUnits({ mem: 26285n, steps: 7850649n }), + }, + { + redeemer_tag: "spend" as const, + redeemer_index: 1, + ex_units: new Redeemer.ExUnits({ mem: 26285n, steps: 7850649n }), + }, + { + redeemer_tag: "spend" as const, + redeemer_index: 2, + ex_units: new Redeemer.ExUnits({ mem: 26285n, steps: 7850649n }), + }, + { + redeemer_tag: "spend" as const, + redeemer_index: 3, + ex_units: new Redeemer.ExUnits({ mem: 26285n, steps: 7850649n }), + }, + ], +}; + +export const evalSample2 = { + utxos: [ + new UTxO.UTxO({ + transactionId: TransactionHash.fromHex( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + ), + index: 0n, + address: Address.fromBech32( + "addr_test1wrzqlyffcf5yq3htqge9h9k29zv6d7ny0rqam6d4c5eqdfgg0h7yw" + ), + assets: Assets.fromLovelace(14_000_000n), + datumOption: new InlineDatum.InlineDatum({ data: Data.fromCBORHex("d87980") }), + scriptRef: new PlutusV2.PlutusV2({ + bytes: Bytes.fromHex( + "59010601000032323232323232323232322223253330083371e6eb8cc014c01c00520004890d48656c6c6f2c20576f726c642100149858cc020c94ccc020cdc3a400000226464a66601e60220042930a99806249334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375c601e002600e0062a660149212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300a37540040046600200290001111199980319b8700100300c233330050053370000890011807000801001118031baa0015734ae6d5ce2ab9d5573caae7d5d0aba201" + ) + }) + }) + ], + transaction: + "84A30081825820FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00018182581D70C40F9129C2684046EB02325B96CA2899A6FA6478C1DDE9B5C53206A51A00D59F800200A10581840000D8799F4D48656C6C6F2C20576F726C6421FF820000F5F6", + redeemersExUnits: [ + { + ex_units: new Redeemer.ExUnits({ mem: 15694n, steps: 3776833n }), + redeemer_index: 0, + redeemer_tag: "spend" as const, + } + ] +}; + +export const evalSample3 = { + utxos: [ + new UTxO.UTxO({ + transactionId: TransactionHash.fromHex( + "fa957d2b1dd37de2281dff8dd58c245baf1a7600067e3512056276c1787eb1e9" + ), + index: 0n, + address: Address.fromBech32( + "addr_test1wqq8ywv7jnzf0uql4s29f6cgzqrcpy0sjn560wjdh0av4fccp0zj6" + ), + assets: Assets.fromRecord({ + lovelace: 4029850n, + aacd6c58a4894b4ca6c3ea429fcd4318b301d9c0eec7f031d08a0780: 1n, + }), + datumOption: new InlineDatum.InlineDatum({ data: Data.fromCBORHex("d87980") }), + scriptRef: new PlutusV2.PlutusV2({ + bytes: Bytes.fromHex( + "5902c70100003323232323232323223222533300532323232323253323300c32533300d300200114a22a66601a66e1d200400114a22a6601c921394d7573742062652065786563757465642061732061206d696e74696e6720706f6c696379206f72207374616b696e672076616c696461746f720014a0601c6ea8c048c04c01454ccc0314ccc030c8c8cc004004010894ccc04c004528099299980819baf0043012301600214a2266006006002602c00264a66601a6004601e6ea80044cdd2a40006602466e9520023301230133010375400297ae04bd700a998072492a4e6f207374616b696e672076616c696461746f7220666f756e6420696e20626561636f6e20696e70757400163012301330133013300f375460246026601e6ea8c94ccc034c008c03cdd50008980998081baa001153300e490129426561636f6e20746f6b656e206e6f7420666f756e64206173207265666572656e636520696e7075740016323300100100422533301200114c0103d87a80001323253330103233001001300b3756602e603060286ea8c05cc060c050dd500191299980b0008a5013253330133371e6eb8c064008044528899801801800980c800899ba548000cc0540092f5c0266008008002602c0046028002294454cc035240124426561636f6e20736372697074206d7573742062652077697468647261776e2066726f6d0014a0294454cc0352411e426561636f6e207374616b6520657865637574696f6e206d697373696e670014a06e1d200014a06eacc040c044c044c044c044c044008dd61807800980798059baa300e001300a3754006600200244a666016002297ae013300c3009300d00133002002300e001149854cc0192411856616c696461746f722072657475726e65642066616c73650013656375c002ae695ce2ab9d5573caae7d5d02ba157449811e581ca168982cd17c45df7c468b527c32b0d3f97b8c297184c8860445e8ee0001" + ), + }), + }), + new UTxO.UTxO({ + transactionId: TransactionHash.fromHex( + "23be0164e07ec84dea989dc4fb58017defc17849679b7dd36d59ae19d0e5a078" + ), + index: 0n, + address: Address.fromBech32( + "addr_test1qpycxt9d7gel0k4mnvaf2kkv0ggmxm57xw4v6dz2krd7anxr5hkplfmepxykzl4c30vy4k9xufmmn8s7jrukzvyclv0shr5358" + ), + assets: Assets.fromRecord({ + lovelace: 26532360n, + a168982cd17c45df7c468b527c32b0d3f97b8c297184c8860445e8ee6f6e652d7761792d626561636f6e2d6465627567: 1n, + }), + datumOption: new InlineDatum.InlineDatum({ data: Data.fromCBORHex("d87980") }), + scriptRef: new PlutusV2.PlutusV2({ + bytes: Bytes.fromHex( + "5916db010000333232323232323232323223223222533300832323232323232323232323232323253330173370e9002180c9baa301d301e0021323300100100222533301d00114a2264a6660346464646464646464a66604c00229444c94ccc09c00454cc09124012e5377617073206d75737420686176652065786163746c79207468726565206b696e6473206f6620626561636f6e730014a0264a6660500022a6604a92012e5377617073206d75737420686176652065786163746c79207468726565206b696e6473206f6620626561636f6e730014a02a66605060560022646464a66604ea66604e66ebc020cdd2a4004660586ea40912f5c0294454cc0a124125426561636f6e73206d757374206265206c6f636b656420696e2073776170207363726970740015330283372c92010953656e7420746f3a2000301600815330283372c9211353686f756c642062652073656e7420746f3a200030163752048294054ccc09d4ccc09d4ccc09cc074c0a4dd50038a5114a0294454cc0a1240126426561636f6e73206d75737420686176652061207374616b65206b65792061747461636865640014a0266602604401601429405281816001981580198150018a99812a492e5377617073206d75737420686176652065786163746c79207468726565206b696e6473206f6620626561636f6e730014a06054002605200264a666044602060486ea800452f5bded8c026eacc0a0c094dd500099198008008031129998138008a60103d87a80001323232325333027337220440042a66604e66e3c0880084c050cc0b0dd3000a5eb80530103d87a8000133006006003375660520066eb8c09c008c0ac008c0a4004c098c09c008c094004c084dd51812002181198120011bab30220013022001301d375460400042660060060022940c08000454cc0612401274d7573742062652065786563757465642061732061207374616b696e672076616c696461746f72001637586038603a603a60326ea8c070004c060dd500719191919191911119299980f180a18101baa0011325333023001153302001e1613232533302500115330220201613232533302700115330240221613232533302900115330260241613232533302b00115330280261613232533302d001153302a0281613232533302f001153302c02a16132325333031001153302e02c16132325333033001153303002e161323253330350011533032030161323253330370011533034032161325333038303b00215333034302a3036375400a264a6660720022a6606c0682c26464a6660760022a6607006c2c264a666078607e00426464a66466076a6660766062607a6ea8c8c8c8c8c8c94ccc104c01cc10cdd51823982400109817198231ba733046375000a6608c6ea000ccc118dd4000a5eb812f5c02a660849211d5554584f206973206d697373696e672076616c696420626561636f6e730014c103d87a8000375a608c002608c0046eb4c110004c110008dd6982100099981381025eb84101000081010000810100008103d879800011191919191919191929919982318008160991919192999825180818261baa30500041533304a0021533304a00313304f37500166609e6ea0024cc13cdd4003998279998252514c103d87a80004c0103d87980004bd700008008008806980718251baa304e304f002300d30493754609a609c609c00266606401097ae10103d87980008103d87980008103d87980001119191919192991998271800816899829999827181e00326103d87a80004c0103d87980003305333304e0034c0103d87a80004c0103d87980003305333304e0024c0103d87a80004c0103d87980004bd700a9998271800813899829999827002a6103d87a80004c0103d87980003305333304e303c0064c0103d87a80004c0103d87980003305333304e0024c0103d87a80004c0103d87980004bd700a9998271800810899829999827002a6103d87a80004c0103d87980003305333304e0034c0103d87a80004c0103d87980003305333304e303c0064c0103d87a80004c0103d87980004bd700a99827a481165554584f206861732077726f6e6720626561636f6e730014bd708103d87980008103d87980008103d87980001b8f375c609e00e6024609c6ea8c148c14c008c044c134dd518288009828801980798259baa304f002375a60960042a64646660906066016264a666092607e60966ea80044c94c8ccc12cc0180a04cc140dd41802801198281ba800a3305037506002004660a066609600e980103d87a80004c0103d87980004bd700a99982598030110998281ba800c3305037506008004660a06ea0c004008cc140ccc12c01d30103d87a80004c0103d87980004bd700998281ba800c330503750014660a06ea0c004008cc140ccc12c01d300103d87a80004c0103d87980004bd701b80007375a609e60986ea800454cc12924012865787065637420536f6d65286e29203d20646963742e67657428746e735f646963742c20232222290016323300100100b22533304e00114c0103d87a8000132323232533304e33722911000021533304e30390021303b33053375000297ae014c103d87a8000133006006003375a60a00066eb8c138008c148008c14000454ccc1214ccc120c00c0944c00c07c5280a9998260050a99824a49284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d879800009929998268008991919299982619b8f0020271330513750600c002660a26ea002ccc144dd400499828999826004260103d87a80004c0103d87980004bd700a99982619b8f002021133051375001a660a26ea0c014004cc144dd400499828999826004260103d87a80004c0103d87980004bd700a99826a481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980001bad304e002375c6098002609e0162a66609a60a00022646464646464a66609e66e3c0100a854ccc13ccdc780101209982a1ba830090033305437506010002660a86ea0030cc150ccc13c02d300103d87a80004c0103d87980004bd700a998282481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980000a99982799b8f0040241533304f3371e0040542660a86ea0c024004cc150dd418040019982a1ba800c3305433304f00b4c0103d87a80004c0103d87980004bd700a998282481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980000a99828249284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980001bad3051004375c609e0066eb4c13c00cdd71826801182800118278058a998252481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d879800018278050a99982418018128a9998260050a99824a481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980000a999826182780509919299982519b8f375c609800404a26609e6ea0c010004cc13cdd4004998279ba80073304f33304a0064c0103d87a80004c0103d87980004bd700a99825a481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980001bad304c001304e00a1533049491284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980000a999824180180f8a9998260050a99824a49284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980000a999826182780509919299982519b8f375c609800403e26609e6ea002ccc13cdd41801800998279ba80073304f33304a0064c0103d87a80004c0103d87980004bd700a99825a481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980001bad304c001304e00a1533049491284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980000a99824a49284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980001b80006370000e6e3c020c028c118dd5182518258011bad30490013049002375a608e002608e0086eb4c11400cdd598208019bae303f00214a2294054ccc0ed4ccc0ecccc0eccdd78018012504a2294454cc0f1241274f666665722061737365742063616e6e6f742062652073616d652061732061736b2061737365740014a02a664646607aa66607a66e3c070cc0980140105288a9981f24811157726f6e6720706169725f626561636f6e00153303e3372c9201076f666665723a2000302c005153303e3372c9210561736b3a2000302c004153303e3002302c37526604c00a0082a6607c600260586ea40705280a99981ea99981e99b8f0163302501a01814a22a6607c66e5924011757726f6e67206f666665725f626561636f6e20666f722000302c375266e2806806054cc0f8c008c0b0dd49981280d00c0a9981f180098161ba901614a02a66607aa66607a66e3c040cc0900500485288a9981f19b964911057726f6e672061736b5f626561636f6e00302c375266e2805004854cc0f8c008c0b0dd49981200a0090a9981f180098161ba901014a02a66607aa66607a600600c294454cc0f92411e737761705f70726963652064656e6f6d696e61746f72206e6f74203e20300014a02a66607a6006010294454cc0f924011c737761705f7072696365206e756d657261746f72206e6f74203e20300014a029405280a50372c9210a52656365697665643a2000372c92010f57617320657870656374696e673a200014a02940dc4240002940c098cc0f8dd48081981f1ba900e4bd7018129981e9ba90153303d375202697ae01533039037163253333330400011533039037161533039037161533039037161375a0022a6607206e2c607a002607a00464a66666607c0022a6606e06a2c2a6606e06a2c2a6606e06a2c26eb400454cc0dc0d458c0ec004c0dcdd50028a9981a8198b0a9981a8198b19299999981e0008a9981a8198b0a9981a8198b0a9981a8198b0a9981a8198b09bae0013039001303900232533333303a0011533033031161533033031161533033031161533033031161375c002606e002606e00464a66666607000220022a6606205e2c2a6606205e2c2a6606205e2c2a6606205e2c606a002606a00464a66666606c0022a6605e05a2c2a6605e05a2c2a6605e05a2c2a6605e05a2c26eb8004c0cc004c0cc008c94cccccc0d000454cc0b40ac5854cc0b40ac5854cc0b40ac5854cc0b40ac584dd7000981880098188011929999998190008a998158148b0a998158148b0a998158148b0a998158148b09bae001302f001302f0023253333330300011533029027161533029027161533029027161533029027161375c002605a002605a00464a66666605c0022a6604e04a2c2a6604e04a2c2a6604e04a2c2a6604e04a2c26eb8004c0ac004c0ac008c94cccccc0b000454cc09408c5854cc09408c5854cc09408c5854cc09408c584dd7000981480098148011929999998150008a998118108b0a998118108b0a998118108b0a998118108b09bae00130270013027002325333333028001153302101f16153302101f16153302101f161375a0022a6604203e2c604a00260426ea800454cc07c07458c94cccccc098004400454cc07c0745854cc07c0745854cc07c0745854cc07c074594ccc074cdc3a4008603e6ea80044c08cc080dd50008a9980f24925416c6c207377617020646174756d73206d75737420626520696e6c696e6520646174756d73001622372866e2922101020033714004002446e50cdc5245010100337140040024464646e50cdc519b8a33714600a6eb8c084008dd71810981100118029bae3021001375c60426044002603a6ea8008c070dd50011299980b98010008a450100001001371e91010022232333001001004003222533301e002100113330030033021002330043020002001374a90001b87480088dcc99801000a441003001001222533333301a00213232323232323300d0020013371491010128000025333016337100069007099b80483c80400c54ccc058cdc4001a410004266e00cdc0241002800690068a9980ba4929576861742061726520796f7520646f696e673f204e6f2049206d65616e2c20736572696f75736c792e001653330190011337149101035b5d2900004133714911035b5f2000375c6036603866600e00266034980102415d003301a375266e2922010129000044bd70111980e26103422c20003301c375266601001000466e28dd718050009bae300b0014bd701bac3017002375a602a0026466ec0dd4180a8009ba730160013754004264a66602e002266e292201027b7d00002133714911037b5f2000375c6032603464646600200200644a6660340022006266446603a98103422c20003301d3752666012012603400466e292201023a2000333009009301b002337146eb8c02c004dd71806000a5eb80c070004cc008008c074004cc0613010342207d0033018375200497ae03756004264a66602e002266e29221025b5d00002133714911035b5f2000375c6032603466600a00266030980102415d0033018375200497ae0223301a4c0103422c20003301a375266600c00c00466e28dd718040009bae30090014bd701bac002133007375a0040022646466e292210268270000132333001001337006e3400920013371491101270000322253330163371000490000800899191919980300319b8000548004cdc599b80002533301933710004900a0a40c02903719b8b33700002a66603266e2000520141481805206e0043370c004901019b8300148080cdc70020011bae00222232330010010042253330170011004133003301900133002002301a0012301400123013301400122323300100100322533300f30050011337149110130000031533300f337100029000099b8a489012d003300200233702900000089980319b8400148050cdc599b803370a002900a240c00066e1d20003001001222533300b3371200490000800899980180199b8400248050cdc599b803370a004900a240c00022930a99804a491856616c696461746f722072657475726e65642066616c73650013656375c0026eb8005241de6578706563742053776170446174756d207b0a20202020706169725f626561636f6e2c0a202020206f666665725f69642c0a202020206f666665725f6e616d652c0a202020206f666665725f626561636f6e2c0a2020202061736b5f69642c0a2020202061736b5f6e616d652c0a2020202061736b5f626561636f6e2c0a20202020737761705f70726963653a20526174696f6e616c2870726963655f6e756d2c2070726963655f64656e292c0a202020202e2e0a20207d3a2053776170446174756d203d206765745f696e6c696e65286f75747075745f646174756d29005734ae7155ceaab9e5573eae815d0aba257489811e581cd87d5887c22fa4989df9b49bd970e3b3db101baf972eb4ac2e8c5802004c011e581caacd6c58a4894b4ca6c3ea429fcd4318b301d9c0eec7f031d08a07800001" + ), + }), + }), + new UTxO.UTxO({ + transactionId: TransactionHash.fromHex( + "a8275eccb3dae1b8ae58837aa22d3c1cbe4df15e5ebc869bd0d710e50b6c44b0", + ), + index: 0n, + address: Address.fromBech32( + "addr_test1qpycxt9d7gel0k4mnvaf2kkv0ggmxm57xw4v6dz2krd7anxr5hkplfmepxykzl4c30vy4k9xufmmn8s7jrukzvyclv0shr5358", + ), + assets: Assets.fromRecord({ + lovelace: 31519030n, + "9e91cf1c285a3029a3517468025d2c9e3ec5a74928627a4603b6dd2d6f6e652d7761792d737761702d6465627567": 1n, + }), + datumOption: new InlineDatum.InlineDatum({ data: Data.fromCBORHex("d87980") }), + scriptRef: new PlutusV2.PlutusV2({ + bytes: Bytes.fromHex( + "591b6201000033232323232323232323232232232323223232322533300e3232323232323232323232323232323232323232323232325333026301f0151323232323232323232533302f3300c020303530323754606a60646ea8c0d400c54ccc0bcccc0280040100084cc0640ac0185280a50330143758606800e6068606a0106eb0c0ccc0d0004c0cc008dd59818800981898188011bab302f001302f302f302f302f001302a3754605a00260526ea806454ccc098c06c0544c8c8c8c8c8c8c94ccc0b4cc028078c0ccc0c0dd5181998181baa30330031533302d3330080010040021533302d330090043015330323374a9001198191ba90294bd7025eb805288a9981724812c426561636f6e20736372697074206e6f74206578656375746564206173207374616b696e67207363726970740014a02940528198091bac30320053032303300637586062606400260620046eacc0bc004c0bcc0bcc0bcc0bcc0bcc0bc004c0a8dd5181680098149baa019153330263370e900200a899191919191929998162999816181098171baa3032303300614a22a6605a920116546865205554584f206d757374206265207370656e740014a02a666058a666058666058602e038941288a51153302d49012c457874656e73696f6e206669656c64206d7573742062652070726573656e7420696e2074686520646174756d0014a02a666058a666058a6660586601000460286606266e95200233031375203897ae04bd700a5113301800101c14a22a6605a92126457874656e73696f6e206d75737420617070726f766520746865207472616e73616374696f6e0014a026602c05000829405280a5037586062606460640046eacc0c0004c0c0c0c0008dd59817000981718171817181718151baa302d00130293754032264646464646466446464646464646464646464646464646464646464646464646464646464646464a66609c604e60a06ea8c15003c54ccc13802054ccc1394ccc1394ccc138c0e40745288981c80b8a511533304e33712900019b8100300a14a22a6609e921194164612063616e206f6e6c79206265206465706f73697465640014a02a66609ca66609c66e24cdc100080899b8200201014a22a6609e9201145377617020726174696f20696e636f727265637400153304f4912e2861736b5f6f202d2061736b5f6929202f20286f666665725f69202d206f666665725f6f29203e3d20707269636500153304f3372c92010761736b5f6f3a2000302c004153304f3372c9210761736b5f693a2000302c00b153304f3372c921096f666665725f693a2000302c00d153304f3372c921096f666665725f6f3a2000302c006153304f32323372c002605c02466e58005241012f003372c9210770726963653a2000302c01114a02a66609c66e25200000214a22a6609e92012b5468652061736b2061737365742063616e6e6f742062652074616b656e2066726f6d20746865207377617000153304f3372c92010b61736b5f676976656e3a2000302c00214a029405280a5014a066e04030014cdc08010049bad30513052002375a60a000260a00046eb4c138004c138008c07cc120dd51826000992999823181f98241baa0011323304c3330474a298103d87a80004c0103d87980003304c304d0013304c304d304e0013304c304d304e304e0014bd701bac304c30493754002297ae10103d87980008101000081010000810100001919198008009bac304d304e304e01d22533304c0011533049490123436f72726573706f6e64696e672073776170206f7574707574206e6f7420666f756e640014c103d87a800013232323232533304d533304d3375e04060a60082a66609a66ebc020004528899299982718238008a99827a48110446174756d206973206d697373696e670014a02a66609c60860022a6609e920114446174756d206d75737420626520696e6c696e650014a02a6609e92113446174756d20646f65736e2774206d617463680014a0609e6ea80045280992999827182398281baa001130363305330543051375400297ae0153304f49011d5377617020636f6e7461696e7320696e76616c6964206f7574707574730014c103d87a800033333333302500204901e01c01a01801601401213300700700530523053002375660a200260a200260986ea8c13c008c13c004cdd2a40086609407e97ae0375a609460960046eb4c124004c124008dd698238009823800992999820181c98211baa001132330463330414a298103d87a80004c0103d87980003304630470013304630473048001330463047304830480014bd701bac304630433754002297ae10103d879800081010000810100008101000019999999980b80981d8080070060050040030021bad30443045002375a6086002607e6ea8c108c10c008dd7182080098208011bae303f001303f002375c607a002607a0046eb8c0ec004c0ec008dd7181c800981c8011bae30370013037002375c606a002606a60626ea80a0dd598191819800981900098171baa30313032302e375460626064660246eb0c0c4004c0c4c0c8008c0b4dd5181800098161baa01c2222222223232323232325333037301030393754607a607c0042603e660786e9ccc0f0dd40029981e1ba80033303c375000297ae04bd700a9981c24811d5554584f206973206d697373696e672076616c696420626561636f6e730014c103d87a8000375a607800260780046eb4c0e8004c0e8008dd6981c000999805804a5eb84101000081010000810100008103d879800011191919191919191929919981e18008098991919192999820180c98211baa3046004153330400021533304000313304537500166608a6ea0024cc114dd4003998229998202514c103d87a80004c0103d87980004bd700008008008806980b98201baa304430450023016303f375460866088608800266602c01097ae10103d87980008103d87980008103d8798000111919191919299199822180080d099824999822181c80326103d87a80004c0103d8798000330493330440034c0103d87a80004c0103d8798000330493330440024c0103d87a80004c0103d87980004bd700a999822180080b899824999822002a6103d87a80004c0103d87980003304933304430390064c0103d87a80004c0103d8798000330493330440024c0103d87a80004c0103d87980004bd700a999822180080a099824999822002a6103d87a80004c0103d8798000330493330440034c0103d87a80004c0103d87980003304933304430390064c0103d87a80004c0103d87980004bd700a99822a481165554584f206861732077726f6e6720626561636f6e730014bd708103d87980008103d87980008103d87980001b8f375c608a00e603660886ea8c120c124008c068c10cdd518238009823801980c18209baa3045002375a60820042a646466607c6052016264a66607e607060826ea80044c94c8ccc104c0180584cc118dd41802801198231ba800a33046375060020046608c66608200e980103d87a80004c0103d87980004bd700a99982098030098998231ba800c33046375060080046608c6ea0c004008cc118ccc10401d30103d87a80004c0103d87980004bd700998231ba800c3304637500146608c6ea0c004008cc118ccc10401d300103d87a80004c0103d87980004bd701b80007375a608a60846ea800454cc10124012865787065637420536f6d65286e29203d20646963742e67657428746e735f646963742c20232222290016323300100100b22533304400114c0103d87a80001323232325333044337229110000215333044302f0021302c33049375000297ae014c103d87a8000133006006003375a608c0066eb8c110008c120008c11800454ccc0f94ccc0f8c00c04c4c00c0405280a9998210050a9981fa49284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d879800009929998218008991919299982119b8f0020161330473750600c0026608e6ea002ccc11cdd400499823999821004260103d87a80004c0103d87980004bd700a99982119b8f002013133047375001a6608e6ea0c014004cc11cdd400499823999821004260103d87a80004c0103d87980004bd700a99821a481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980001bad3044002375c6084002608a0162a666086608c0022646464646464a66608a66e3c01006454ccc114cdc780100b0998251ba830090033304a37506010002660946ea0030cc128ccc11402d300103d87a80004c0103d87980004bd700a998232481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980000a99982299b8f004016153330453371e0040322660946ea0c024004cc128dd41804001998251ba800c3304a33304500b4c0103d87a80004c0103d87980004bd700a998232481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980000a99823249284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980001bad3047004375c608a0066eb4c11400cdd71821801182300118228058a998202481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d879800018228050a99981f18018098a9998210050a9981fa481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980000a999821182280509919299982019b8f375c608400402826608a6ea0c010004cc114dd4004998229ba8007330453330400064c0103d87a80004c0103d87980004bd700a99820a481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980001bad3042001304400a153303f491284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980000a99981f18018080a9998210050a9981fa49284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980000a999821182280509919299982019b8f375c608400402226608a6ea002ccc114dd41801800998229ba8007330453330400064c0103d87a80004c0103d87980004bd700a99820a481284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980001bad3042001304400a153303f491284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980000a9981fa49284e6f2065787472616e656f75732061737365747320616c6c6f77656420696e20746865205554584f0014bd708101000081010000810100008103d87980001b80006370000e6e3c020c04cc0f0dd5182018208011bad303f001303f002375a607a002607a0086eb4c0ec00cdd5981b8019bae3035002371090001111919980080080200191129998180010800899980180198198011980218190010009111929998149919299981598120010992999816181298171baa001132533302d3026302f375400226603200c6eb8c0ccc0c0dd5000801981918179baa0010023031302e37540060022a666054604600226600c0086060605a6ea800852818159baa00114a22a660549201225374616b696e672063726564656e7469616c20646964206e6f7420617070726f76650014a0605c605e60566ea800c88c8cc00400400c894ccc0b0004528099299981499baf004302b302f00214a2266006006002605e00244a66604a66e24009200014a22a66604a6034604e6ea80044c94ccc098cdc40018008a5115330273372c9211553776170206973206c6f636b656420756e74696c2000300400315330273372c9211043757272656e742074696d652069732000300400114a06eb4c0acc0a0dd50008a9981324813053776170206973206c6f636b656420616e64207472616e73616374696f6e206973206d697373696e6720626f756e64730014a046e64cc008dd4000a441003001001222533333302b00213232323232323300c0020013371491010128000025333027337100069007099b80483c80400c54ccc09ccdc4001a410004266e00cdc0241002800690068a9981424929576861742061726520796f7520646f696e673f204e6f2049206d65616e2c20736572696f75736c792e0016533302a0011337149101035b5d2900004133714911035b5f2000375c6058605a66600e00266056980102415d003302b375266e2922010129000044bd701119816a6103422c20003302d375266601001000466e28dd718088009bae300a0014bd701bac3028002375a604c0026466ec0dd418130009ba730270013754004264a666050002266e292201027b7d00002133714911037b5f2000375c6054605664646600200200644a6660560022006266446605c98103422c20003302e3752666012012605600466e292201023a2000333009009302c002337146eb8c048004dd71805800a5eb80c0b4004cc008008c0b8004cc0a53010342207d0033029375200497ae03756004264a666050002266e29221025b5d00002133714911035b5f2000375c6054605666600a00266052980102415d0033029375200497ae0223302b4c0103422c20003302b375266600c00c00466e28dd718078009bae30080014bd701bac002133006375a0040022646466e292210268270000132333001001337006e3400920013371491101270000322253330273371000490000800899191919980300319b8000548004cdc599b80002533302a33710004900a0a40c02903719b8b33700002a66605466e2000520141481805206e0043370c004901019b8300148080cdc70020011bae00222232330010010042253330280011004133003302a00133002002302b001230253026001223233001001003225333021301a00113371491101300000315333021337100029000099b8a489012d003300200233702900000089980299b8400148050cdc599b803370a002900a240c00066002002444a66603c66e2400920001001133300300333708004900a19b8b3370066e1400920144818000488c088c07cdd518111811980f9baa302230233300300200122533301b3010301d375400226464a66603a602c603e6ea80044cc088008cc088c08cc080dd5000a5eb8054cc0792411b436f756c64206e6f742066696e642073637269707420696e7075740016323300100100422533302200114c0103d87a80001323253330203375e601260466ea80080144c020cc0940092f5c0266008008002604c00460480026042603c6ea800454cc071241125554584f206d757374206265207370656e740016374a90001180f00091299980c198021802991980080080111299980f0008a5eb7bdb1804c8c8c8c94ccc078cdc8a45000021533301e300900210031005133023337606ea4008dd3000998030030019bab3020003375c603c00460440046040002004294454cc0652412c426561636f6e20736372697074206e6f74206578656375746564206173206d696e74696e6720706f6c6963790014a06e3d22010022323300100100322533301c00114a0264a66603266e3cdd7180f8010020a51133003003001301f001300100122533301800114bd7009980c980b180d00099801001180d80098099baa007375c602c602e602e602e602e602e602e602e602e602e0046eb4c054004c044dd50040a4c2a6601e9211856616c696461746f722072657475726e65642066616c7365001365632533300d300600115333011301037540062930a998070058b0a99980698010008a99980898081baa003149854cc03802c5854ccc034cdc3a40080022a66602260206ea800c526153300e00b161533300d3370e90030008a99980898081baa003149854cc03802c5854cc03802c58c038dd50011b87480094cccccc048004400454cc02c0205854cc02c0205854cc02c0205854cc02c020594ccc020c004c028dd500109929998068008a998050040b0991929998078008a998060050b0991929998088008a998070060b0991929998098008a998080070b09919299980a8008a998090080b09919299980b8008a9980a0090b09919299980c8008a9980b00a0b09919299980d8008a9980c00b0b09919299980e8008a9980d00c0b09919299980f8008a9980e00d0b0991929998108008a9980f00e0b0992999811181280109924ca66603c602e60406ea80144c94ccc08c00454cc080078584c8c94ccc09400454cc088080584c94ccc098c0a400852615330230211632533333302a0011533023021161533023021161533023021161375a0022a660460422c604e002604e00464a6666660500022a6604203e2c2a6604203e2c2a6604203e2c26eb400454cc08407c58c094004c084dd50028a9980f80e8b0a9980f80e8b1929999998130008a9980f80e8b0a9980f80e8b0a9980f80e8b0a9980f80e8b09bae00130230013023002325333333024001153301d01b16153301d01b16153301d01b16153301d01b161375c0026042002604200464a66666604400220022a660360322c2a660360322c2a660360322c2a660360322c603e002603e00464a6666660400022a6603202e2c2a6603202e2c2a6603202e2c2a6603202e2c26eb8004c074004c074008c94cccccc07800454cc05c0545854cc05c0545854cc05c0545854cc05c054584dd7000980d800980d80119299999980e0008a9980a8098b0a9980a8098b0a9980a8098b0a9980a8098b09bae0013019001301900232533333301a0011533013011161533013011161533013011161533013011161375c002602e002602e00464a6666660300022a6602201e2c2a6602201e2c2a6602201e2c2a6602201e2c26eb8004c054004c054008c94cccccc05800454cc03c0345854cc03c0345854cc03c0345854cc03c034584dd70009809800980980119299999980a0008a998068058b0a998068058b0a998068058b0a998068058b09bae00130110013011002325333333012001153300b00916153300b00916153300b009161375a0022a660160122c601e00260166ea800854cc02401c58dc3a4000a66666601c00220022a6600e00a2c2a6600e00a2c2a6600e00a2c2a6600e00a2c6eb80052411672656465656d65723a205377617052656465656d657200490110646174756d3a2053776170446174756d005734ae7155ceaab9e5573eae815d0aba257489811e581caacd6c58a4894b4ca6c3ea429fcd4318b301d9c0eec7f031d08a07800001" + ), + }), + }), + new UTxO.UTxO({ + transactionId: TransactionHash.fromHex( + "b8fd5caa1dc06c6bb1c713cf9f948012454cfdc028a34c47270dd253780fd20e", + ), + index: 0n, + address: Address.fromBech32( + "addr_test1qpycxt9d7gel0k4mnvaf2kkv0ggmxm57xw4v6dz2krd7anxr5hkplfmepxykzl4c30vy4k9xufmmn8s7jrukzvyclv0shr5358", + ), + assets: Assets.fromRecord({ + lovelace: 16649530n, + "8ed3a2a3871f49e25905cc7d057c94ecf6162e9502fc22caf30406ef6f6e652d7761792d666f727761726465722d6465627567": 1n, + }), + datumOption: new InlineDatum.InlineDatum({ data: Data.fromCBORHex("d87980") }), + scriptRef: new PlutusV2.PlutusV2({ + bytes: Bytes.fromHex( + "590de301000033232323232323232323223223232322533300932323232323232323232323232323232533301953330193330193375e6e9c0053010180004a09445288a9980d2481234174206c65617374206f6e652073776170206d7573742062652076616c6964617465640014a02a66603264a666034a666034646002603a6ea8c084c8ccc004004010cc084ccc07128a6103d87a80004c0103d879800033021374e00a97ae02225333022002100113330030033025002323232330263330215333021300730233754604e00820022941300103d87a80004c0103d879800033026302730280024bd70180318111baa30260013232323232323232330010013758605a605c01444a666058002297ae1103d87980008101800009919299981519299981599baf3031302e375400600c266e1c00401c52819980b1bab30303031302d375400401000e26605e66605494530103d87a80004c0103d87980003302f374e00297ae01323303033302b3011302d37546062002980103d87a80004c0103d879800033030374e660600066eb0c0c4c0c80052f5c0660080080026060004605c002602466054602466054605600c97ae03302a30123302a30123302a30123302a302b302c0064bd7025eb812f5c097ae0333010375660540080040026eb8c0a4c0a8008dd7181400098141814181400098119baa002302237546464a666042603660466ea80044c054dd6181398121baa00115330223372c9211652656465656d6572206d697373696e6720666f723a200037320042c646600200201044a66604c002298103d87a80001323253330243371e6eb8c05c0080144c044cc0a4dd380125eb804cc010010004c0a8008dd618140009bae30253026302630263026302630263022375400260480046e21200014a229405288a9980da481214e6f7420616c6c2073776170732068617665206265656e20666f727761726465640014a0646600200202a44a66603e002297ae0133020374e64660426ea4dca191998008009bac302032337606ea0c080004dd398108009baa0024890022253330230021001133300300330260023233714004002646a6666660500022ecc5d98bb312323300100132333001001375a00697ae022253330255333025301f00214a22603e9040020800899980180199b830024820010cc0a8dd419b860024820010004894ccc09c004522010013322337160040026eb4c0a4004cc008008c0a80045d7000981280119810800a5eb80c084004cc008008c0880044c8cc004004008894ccc07c004528899299980e1919191929998102999810180d0008a51153330203371e0049110013371000290406d62048a5014a22a660429201125377617020697320696e636f6d706c6574650014a06660166eacc09400c004dd7181298130011bae30240013024001301f375460440042660060060022940c0880045280a503232330010013758604000844a66603e002297ae013232533301d300b301f3754002266008008004266044604660406ea8004cc010010008c94ccc074c05cc07cdd50008980519811181198101baa0014bd700a6103d87a8000323232323232533302253330223375e605000466e95200233027375203e97ae015333022301c3024375400229445280a5013253330233371e6eb8c0a4c0a8c0a8c0a8c0a8c0a8c098dd50008058980819814000a5eb805300103d87a800032533302700115330244911a496e76616c6964206f6e652d776179207377617020646174756d00161325333028001153302549011a496e76616c6964206f6e652d776179207377617020646174756d00161325333029001153302649011a496e76616c6964206f6e652d776179207377617020646174756d0016132533302a001153302749011a496e76616c6964206f6e652d776179207377617020646174756d0016132533302b001153302849011a496e76616c6964206f6e652d776179207377617020646174756d0016132533302c001153302949011a496e76616c6964206f6e652d776179207377617020646174756d0016132533302d001153302a49011a496e76616c6964206f6e652d776179207377617020646174756d0016132533302e001153302b49011a496e76616c6964206f6e652d776179207377617020646174756d0016132533302f001153302c49011a496e76616c6964206f6e652d776179207377617020646174756d00161325333030001153302d49011a496e76616c6964206f6e652d776179207377617020646174756d00161325333031001153302e49011a496e76616c6964206f6e652d776179207377617020646174756d00161533303130340011301a33032374c01e660646ea4c070c0cc024cc0c8dd4980e1819804198191ba9301c30330063303237526038606600a660646ea4c070c0cc008cc0c8dd4980e1819800a5eb8054cc0b92411a496e76616c6964206f6e652d776179207377617020646174756d00163033001303200130310013030001302f001302e001302d001302c001302b001302a00153330223370e900218121baa0031325333023533333302b00114a229405280a5014a0264a666050002297ae010013758604c6466ec0dd418130009ba730270013754002297ae0302830253754006297ae014c103d87a80003027302800130233754604c008604a604c0046eacc090004c090004c07cdd518111811980f9baa302200230220013232533301a3370e9002180e1baa002132533301b3015301d3754002264a6660386014603c6ea80044dd71811180f9baa0010033021301e37540020046040603a6ea800800454cc06924012b536372697074206d757374206265206578656375746564206173207374616b65207769746864726177616c0016301e301f0033758603a603c603c00260326ea8c070004c060dd500691119299980c1803180d1baa0011480004dd6980f180d9baa0013253330183006301a37540022980103d87a8000132330010013756603e60386ea8008894ccc078004530103d87a8000132323232533301e337220100042a66603c66e3c0200084c02ccc08cdd4000a5eb80530103d87a8000133006006003375a60400066eb8c078008c088008c080004c8cc004004010894ccc0740045300103d87a8000132323232533301d337220100042a66603a66e3c0200084c028cc088dd3000a5eb80530103d87a80001330060060033756603e0066eb8c074008c084008c07c004dd2a40006e1d200225333012533333301a00114a029405280a5014a226eb800454cc04ccdcb24920436f756c64206e6f7420636f6e7665727420746f204279746541727261793a2000373266004002910100163001001222533333301a00213232323232323300d0020013371491010128000025333016337100069007099b80483c80400c54ccc058cdc4001a410004266e00cdc0241002800690068a9980ba4929576861742061726520796f7520646f696e673f204e6f2049206d65616e2c20736572696f75736c792e001653330190011337149101035b5d2900004133714911035b5f2000375c6036603866600e00266034980102415d003301a375266e2922010129000044bd70111980e26103422c20003301c375266601001000466e28dd718050009bae300b0014bd701bac3017002375a602a0026466ec0dd4180a8009ba730160013754004264a66602e002266e292201027b7d00002133714911037b5f2000375c6032603464646600200200644a6660340022006266446603a98103422c20003301d3752666012012603400466e292201023a2000333009009301b002337146eb8c02c004dd71806000a5eb80c070004cc008008c074004cc0613010342207d0033018375200497ae03756004264a66602e002266e29221025b5d00002133714911035b5f2000375c6032603466600a00266030980102415d0033018375200497ae0223301a4c0103422c20003301a375266600c00c00466e28dd718040009bae30090014bd701bac002133007375a0040022646466e292210268270000132333001001337006e3400920013371491101270000322253330163371000490000800899191919980300319b8000548004cdc599b80002533301933710004900a0a40c02903719b8b33700002a66603266e2000520141481805206e0043370c004901019b8300148080cdc70020011bae00222232330010010042253330170011004133003301900133002002301a0012301400123013301400122323300100100322533300f30090011337149110130000031533300f337100029000099b8a489012d003300200233702900000089980299b8400148050cdc599b803370a002900a240c00066002002444a66601866e2400920001001133300300333708004900a19b8b3370066e14009201448180004526153300a4911856616c696461746f722072657475726e65642066616c73650013656323300100100322533300d00114984c8cc00c00cc044008c8c94ccc02cc014c034dd500089929998080008a998068058b0991929998090008a998078068b0992999809980b0010a4c2a6602001c2c64a66666602e0022a6602001c2c2a6602001c2c2a6602001c2c2a6602001c2c26eb8004c050004c050008c94cccccc05400454cc0380305854cc0380305854cc0380305854cc038030584dd7000980900098071baa001153300c00a1653333330120011001153300b00916153300b00916153300b00916153300b00916300f001370e900029999998068008a998030020b0a998030020b09bac001153300600416153300600416375c0029211672656465656d65723a204c6973743c506172616d733e005734ae7155ceaab9e5573eae815d0aba257489811e581cd87d5887c22fa4989df9b49bd970e3b3db101baf972eb4ac2e8c58020001" + ), + }), + }), + new UTxO.UTxO({ + transactionId: TransactionHash.fromHex( + "9dec9370f3c40d5934f4ea67dcacf22f0cdb74acbbecf4638ae141748e9c6601", + ), + index: 0n, + address: Address.fromBech32( + "addr_test1zrv86ky8cgh6fxyalx6fhktsuweakyqm47tjad9v96x9sqkz4dj9nfc7w9et2y92mddkpak62wn3zmj9eflkp3q5tfsskd40un", + ), + assets: Assets.fromRecord({ + lovelace: 2_952_350n, + "aacd6c58a4894b4ca6c3ea429fcd4318b301d9c0eec7f031d08a07809cc2aa27327ee7b4ca48c0cf2fa035579cfc1d16fcc6222bd673b02dfc393e55": 1n, + "aacd6c58a4894b4ca6c3ea429fcd4318b301d9c0eec7f031d08a0780c784a5780f4637fa9027e6eedabc24e425a458a481b1be6ae4dee6d7081dbb7b": 1n, + "aacd6c58a4894b4ca6c3ea429fcd4318b301d9c0eec7f031d08a0780e6bc4fcf950a505075ce1e9206c48a58dbb4255fdafdec9617f12c538ed025b1": 1n, + "6af660f258a83733ab5bbf1c779286d3d9c7881ccad209fe6d0ffc9b4d5954455354544f4b454e32": 150_000_000n, + }), + datumOption: new InlineDatum.InlineDatum({ + data: Data.fromCBORHex( + "d8799f0058209cc2aa27327ee7b4ca48c0cf2fa035579cfc1d16fcc6222bd673b02dfc393e55581cc993b4822e24f62fbb291bef2feea56dc70d93122dcb15715b0427ae4c4d5954455354544f4b454e315820c784a5780f4637fa9027e6eedabc24e425a458a481b1be6ae4dee6d7081dbb7b581c6af660f258a83733ab5bbf1c779286d3d9c7881ccad209fe6d0ffc9b4c4d5954455354544f4b454e325820e6bc4fcf950a505075ce1e9206c48a58dbb4255fdafdec9617f12c538ed025b1d8799f0302ff581c5724eab01c199500967c1f96e827811e6618b9bf521f6b46c4270078582072b35c5f04b28f75518ef99c2fc9235d4b940849580d878510d3a24191c67b72ff", + ), + }), + }), + new UTxO.UTxO({ + transactionId: TransactionHash.fromHex( + "9dec9370f3c40d5934f4ea67dcacf22f0cdb74acbbecf4638ae141748e9c6601", + ), + index: 1n, + address: Address.fromBech32( + "addr_test1qzga90w88cw7p5kvwaknm3893k6ap672xaed4szj4fylmjxz4dj9nfc7w9et2y92mddkpak62wn3zmj9eflkp3q5tfsskuvgvd", + ), + assets: Assets.fromRecord({ + lovelace: 9_997_525_540n, + "c993b4822e24f62fbb291bef2feea56dc70d93122dcb15715b0427ae4d5954455354544f4b454e31": 2_000_000_000n, + "6af660f258a83733ab5bbf1c779286d3d9c7881ccad209fe6d0ffc9b4d5954455354544f4b454e32": 2_850_000_000n, + }), + }), + ], + redeemersExUnits: [ + { + ex_units: new Redeemer.ExUnits({ mem: 125172n, steps: 35018665n }), + redeemer_index: 0, + redeemer_tag: "spend" as const, + }, + { + ex_units: new Redeemer.ExUnits({ mem: 53839n, steps: 19027408n }), + redeemer_index: 0, + redeemer_tag: "mint" as const, + }, + { + ex_units: new Redeemer.ExUnits({ mem: 284465n, steps: 88839652n }), + redeemer_index: 0, + redeemer_tag: "reward" as const, + }, + { + ex_units: new Redeemer.ExUnits({ mem: 72501n, steps: 20055562n }), + redeemer_index: 1, + redeemer_tag: "reward" as const, + }, + ], + transaction: + "84ac00828258209dec9370f3c40d5934f4ea67dcacf22f0cdb74acbbecf4638ae141748e9c6601008258209dec9370f3c40d5934f4ea67dcacf22f0cdb74acbbecf4638ae141748e9c66010101828258390091d2bdc73e1de0d2cc776d3dc4e58db5d0ebca3772dac052aa49fdc8c2ab6459a71e7172b510aadb5b60f6da53a7116e45ca7f60c4145a61821a002d0c9ea1581c6af660f258a83733ab5bbf1c779286d3d9c7881ccad209fe6d0ffc9ba14c4d5954455354544f4b454e321a08f0d1808258390091d2bdc73e1de0d2cc776d3dc4e58db5d0ebca3772dac052aa49fdc8c2ab6459a71e7172b510aadb5b60f6da53a7116e45ca7f60c4145a61821b0000000253dcc429a2581c6af660f258a83733ab5bbf1c779286d3d9c7881ccad209fe6d0ffc9ba14c4d5954455354544f4b454e321aa9df8c80581cc993b4822e24f62fbb291bef2feea56dc70d93122dcb15715b0427aea14c4d5954455354544f4b454e311a77359400021a00095dfb031a039152bc05a2581df05724eab01c199500967c1f96e827811e6618b9bf521f6b46c427007800581df0c0c837b81dd43f25cc77446ad70d669379bdab898d83922adff1d86500081a0391502809a1581caacd6c58a4894b4ca6c3ea429fcd4318b301d9c0eec7f031d08a0780a35820e6bc4fcf950a505075ce1e9206c48a58dbb4255fdafdec9617f12c538ed025b1205820c784a5780f4637fa9027e6eedabc24e425a458a481b1be6ae4dee6d7081dbb7b2058209cc2aa27327ee7b4ca48c0cf2fa035579cfc1d16fcc6222bd673b02dfc393e55200b58203c95151f49608a1dde1bc4cd4f25a50733e271792fec4b05f0f949ac599c8bb70d818258209dec9370f3c40d5934f4ea67dcacf22f0cdb74acbbecf4638ae141748e9c660101108258390091d2bdc73e1de0d2cc776d3dc4e58db5d0ebca3772dac052aa49fdc8c2ab6459a71e7172b510aadb5b60f6da53a7116e45ca7f60c4145a61821b000000025399d6e4a2581cc993b4822e24f62fbb291bef2feea56dc70d93122dcb15715b0427aea14c4d5954455354544f4b454e311a77359400581c6af660f258a83733ab5bbf1c779286d3d9c7881ccad209fe6d0ffc9ba14c4d5954455354544f4b454e321aa9df8c80111a004c4b401284825820fa957d2b1dd37de2281dff8dd58c245baf1a7600067e3512056276c1787eb1e90082582023be0164e07ec84dea989dc4fb58017defc17849679b7dd36d59ae19d0e5a07800825820a8275eccb3dae1b8ae58837aa22d3c1cbe4df15e5ebc869bd0d710e50b6c44b000825820b8fd5caa1dc06c6bb1c713cf9f948012454cfdc028a34c47270dd253780fd20e00a10584840000d87b80821a0001e8f41a021657a9840100d879808219d24f1a012255d08403009fd8799f581c91d2bdc73e1de0d2cc776d3dc4e58db5d0ebca3772dac052aa49fdc8581cc2ab6459a71e7172b510aadb5b60f6da53a7116e45ca7f60c4145a61ffff821a000457311a054b95e4840301d87980821a00011b351a0132060af5f6", +}; + +export const evalSample4 = { + utxos: [ + new UTxO.UTxO({ + transactionId: TransactionHash.fromHex( + "fd0fe35440a60946923a95a227cd7b79b0215e7356487aa083aeea5eb3ad1c2f" + ), + index: 0n, + address: Address.fromBech32( + "addr_test1xqpvrw65753pjp62vcl2lqtrlxf77yufg5uhparz5qhf60czcxa4fafzryr55e3747qk87vnaufcj3fewr6x9gpwn5lsekxee5" + ), + assets: Assets.fromLovelace(50_000_000n), + }), + new UTxO.UTxO({ + transactionId: TransactionHash.fromHex( + "d6da036c1aeb7680323258c763a2a6e25be9b280c2a8fedd5e43cb89730fdadf" + ), + index: 0n, + address: Address.fromBech32( + "addr_test1vq7uu7zy7d4j8wxrly90hfq25xyw0uwn7m52e5w4gnk3m2gprf2za" + ), + assets: Assets.fromLovelace(4_366_030n), + scriptRef: new PlutusV3.PlutusV3({ + bytes: Bytes.fromHex( + "5910ff0101003323232323232323232323222598009919191919299919805980098069baa002132323259800803454cc8cc03cc004c044dd50038992cc00400601d13259800800c4c9660020030108992cc0040062b3001301a0028acc004c014c054dd5001c4c9660020030128992cc004006027013809c04e26464b300100180ac4c96600200301680b405a02d1323259800800c062264b300100180cc0660330198992cc004c08c00e2b3001300e301e375401513259800800c06e264b300100180e407203901c899192cc00400603d13259800800c07e03f01f80fc4c8c9660020030218992cc004006045022811408a264b3001302c003899191919191919191919191929981919b964910d6368616c6c656e676549643a20003732660026ea401d2201001325330333372c9201157369676e616c73206368616c6c656e676549643a20003732660046002606a6ea80312201001325330343372c920114697320666f72206576616c756574696f6e3f3a2000598009814981a9baa30013036375406114910474727565008a490566616c73650040cc2646464b30013028303837540031325980099b8748010c0e4dd5000c4c94cc0e4cdcb249095a6b446174756d3a2000373266010002910100159800800c566002605460746ea8006264b300100181c44c96600200303981cc0e60731323259800800c0ee264b300100181e40f207903c899192cc00400607d13259800800c566002608e005159800981918211baa0018992cc00400608113259800800c106083041820c4c8c9660020030438992cc004006089044822411226464b300100182344c966002003047823c11e08f1323259800800c126264b3001001825412a09504a899192cc00400609913259800800c13609b13259800982b001c4c8cc00400400888c96600200515330533372c9201117665726966696564207573657249643a20003732660446ea406122010015330533372c9201087573657249643a2000373266044603c60aa6ea80b122010015980099b8f018375c603c60aa6ea80b22a660a666e592410f766572696669656420686173683a20003732660446ea405522010015330533372c920106686173683a2000373266044604060aa6ea80b122010015980099b8f015375c604060aa6ea80b22646464b300130473057375400313232598009824982c9baa001899191919192cc004c138c178dd500144c94cc178cdcb24811175736572496420286e756d626572293a200037326605a6ea0021220100153305e3372c9201127077644861736820286e756d626572293a200037326605a6ea0019220100153305e3372c9201146368616c6c656e676520286e756d626572293a200037326605a6ea0005220100153305e3372c92010a6f766572666c6f773a200037326605a6ea000922010015980099919119bc6337886eecdd7181618319baa03937846eb8c0bcc18cdd501c99bc53378a66f10ddd9bae302c306337540426f08dd7181798319baa0213378864b30010018a998312491077726f6e6720766b5f69632073697a6500168994c004c1a400a00737760028020dd71833800a0ca375860cc60ce60ce60ce60ce60c66ea8084de11bae302e3063375404266f10ddd9bae302e306337540726f08dd7183318339833983398319baa0213001001222259800801c400626464b30010048b46600200d00198350024cddb00199bb8375a60d20086eec00900620ce3069004375c60ce0068328cc188dd4004198311ba8006330623750002660c46ea0020cc188dd4000998311ba80064bd704528c54cc1792401267a6b5f7665726966792870726f6f662c207075626c69632c207a6b657929203f2046616c73650014a082e8dd69831182f9baa0028a9982ea49b86578706563742028536f6d65286368616c6c656e6765292c206f766572666c6f7729203d0a2020202020207768656e207363616c61722e6e6577286e756d4368616c6c656e676529206973207b0a20202020202020204e6f6e65202d3e20287363616c61722e6e6577286d6f645f696e7465676572286e756d4368616c6c656e67652c207363616c61722e6669656c645f7072696d6529292c2031290a20202020202020206e202d3e20286e2c2030290a2020202020207d001641706eb4c184c188008c180004c96600260a060b86ea80062660be601066e180092082808080e0fffffffffbdfe5ffbf81a4fbceaa80bbe88488b0e79983a9dfcea9a69dedbe0e3305f4c10101004bd7044cc17c004cc17d30010100004bd7020b4300700133794944dd71813982d9baa032375a60ba60b46ea80062a660b092014265787065637420536f6d65286861736829203d207363616c61722e66726f6d5f6279746561727261795f6269675f656e6469616e287369676e616c732e68617368290016415c60066eb8c090c164dd50181bad305b30583754003153305649014665787065637420536f6d652875736572496429203d207363616c61722e66726f6d5f6279746561727261795f6269675f656e6469616e287369676e616c732e757365724964290016415460026eb8c080c15cdd50171180119bca4a20024b30015980099b8948000006266e200052082808080e0fffffffffbdfe5ffbf81a4fbceaa80bbe88488b0e79983a9dfcea9a69dedbe0e8a50414d1302a33058375000297ae08a60103d87a8000414d15330534912365787065637420766572696669656448617368203d3d207369676e616c732e6861736800164149153305349127657870656374207665726966696564557365724964203d3d207369676e616c732e7573657249640016414913259800800c14a0a505282944c8c00cc16c010dd7000a0b630580024158600400504e414c6eb000609b04d415860a60028288c14c00cdd7000a0a63050001413860a00066eb80050501826800a096304d003375c0028268c12800504818250019bae0014128608e0028228c10cdd5000c0fd04040fd04440fe07f03f81fa0903045001410c608a0066eb80050451821000a0803042003375c0028210c0fc00503d181d9baa00181ba07081bc0de06f0374100607a60746ea80062a6607092012765787065637420496e6c696e65446174756d286461746129203d206f75747075742e646174756d001640dc600860726ea8c0f0c0f4c0e4dd5181e181c9baa0018a9981ba497565787065637420536f6d65286163636f756e74496e70757429203d0a2020202020207265666572656e63655f696e707574730a20202020202020207c3e2066696e645f6163636f756e745f696e70757428706172616d732e706f6c6963795f69642c20706172616d732e61737365745f6e616d6529001640d86644646600200202044b30010018a60103d87a8000899192cc004c0c4c9660026064607c6ea80062900044dd69821181f9baa00140f064b30013032303e375400314c103d87a8000899198008009bab30433040375400444b30010018a6103d87a80008991919192cc004cdc8806001456600266e3c03000a260326608e6ea00052f5c114c0103d87a8000410913300600600341086eb4c11000cdd7182100118230011822000a08440f064660020026eacc108c10cc0fcdd518211821981f9baa0032259800800c530103d87a80008991919192cc004cdc8806001456600266e3c03000a260306608c6e980052f5c114c0103d87a8000410513300600600341046eacc10c00cdd7182080118228011821800a082898091982000125eb8226600800800281d8c104008c0fc00503d1bae3001303837540646eb8c010c0e0dd50191181d800acc004c0a4c0d4dd51800981b1baa0308acc004cdc79bae30023036375401a6eb8c008c0d8dd5006c5268a9981a2492d657870656374207369676e616c732e6368616c6c656e6765203d3d207369676e616c732e6368616c6c656e6765001640cd15980099b8f375c6004606c6ea8034026293454cc0d1240127657870656374207369676e616c732e6368616c6c656e6765203d3d206368616c6c656e67654964001640cc81988c0e4c0e8c0e80048c0e0c0e4004c004004889660026e29221022c20008998029bad0020018991919b8a488102682700001329800800ccdc01b8d0024800666e2922010127000034004444b3001337100049000440062646465300100699b800054800666e2ccdc00012cc004cdc4001240291481822903720723371666e000056600266e2000520148a40c11481b9039002200c3370c004901019b8300148080cdc7002001206c375c00494c00400e26464646464646601800400266e2922010128000025980099b880034803a266e0120f2010038acc004cdc4001a41000513370066e01208014003480362c81b90372cc004006266e292201035b5d2900005899b8a489035b5f20009800800ccdc52441025d2900005914c00402600530060014025229800804c00a00280490082074375860700046eb4c0d8004c8cdd81ba83036001374e606e0026ea800e264b3001001899b8a4881027b7d00003899b8a489037b5f20003232330010010032259800800c400e2b3001303e0018994c0040266074003337149101023a20009800804cc0ec0060088049009181e800c4ca6002013303a00199b8a489023a20009800804cc0ec006600c66006006607e0048049009181e800a07640ec66e2922102207d0000340e06eac00e264b3001001899b8a489025b5d00003899b8a489035b5f20009800800ccdc52441015d00003914c00401e0053004001401d229800803c00a00280390062070375800681d84444646600200200a44b30010018802c5660026076003133003303a001005899802181d00099801001181d800a07040e044646600200200644b30013023001899b8a4890130000038acc004cdc4000a40011337149101012d0033002002337029000000c4cc014cdc2000a402866e2ccdc019b8500148051206000340c48188c0040048896600266e2400920008800c6600200733708004900a4cdc599b803370a004900a240c0002801902e19191b9400137660026464646464646460106606c6e9cc014dd6181b8019981b1ba730053758606e0086606c6e9e60026eb0c0dc00a97ae0911919191981d98069981d981e0019981d9ba9300c37566078004660766ea4c8c966002605400314881008acc004c0b800626eb8c0f8c0ecdd500144c8c8dca0009bb3001303e303b375400481c1038181c9baa001303c0013303b303c303d0014bd70002181e000981d800981b1baa00240186606c6ea4c01cdd5981b8009981b181b981c000a5eb80c0dcc0dc004c0d8004c0d4004c0c0dd501394c00400697ae0911981a181a98191baa0020014008444646600200200844b3001001880244cc00cc0d8004cc008008c0dc00503411bb3374c0026e9520003758605c605e60566ea8088c0b4c0b8008c0b0004c0a0dd500ec08d0291bae00140b060520028138c0a400cdd7000a05230260014090604c0066eb80050261811800a042301f375401501a407101a40806eb80050231810000a03c3020003375c0028100c07400501b180e8019bae0014074603400280c0c058dd5001c04501340450174046023011808a03630180014058603000500f807c03e01e80c8c05800501418091baa007370e9000006403201900c806202c301330140023012001300e37540046e1d200216300f3010002300e001300e002300c00130083754003149a2a6600c9211856616c696461746f722072657475726e65642066616c7365001365640142a6600692011272656465656d65723a2052656465656d6572001615330024914a657870656374205a6b446174756d207b207573657249643a2076657269666965645573657249642c20686173683a207665726966696564486173682c207a6b6579207d203d206461746100165734ae7155ceaab9e5573eae815d0aba2574898130d8799f581cb8a5e329b500a66376047165cdfce62c3ecf245fd81d101533f814224a466f6e74757323303030d87980ff0001" + ), + }), + }), + ], + redeemersExUnits: [ + { + redeemer_tag: "cert" as const, + redeemer_index: 0, + ex_units: new Redeemer.ExUnits({ mem: 272836n, steps: 82963426n }), + }, + ], + transaction: + "84aa0081825820fd0fe35440a60946923a95a227cd7b79b0215e7356487aa083aeea5eb3ad1c2f00018182581d603dce7844f36b23b8c3f90afba40aa188e7f1d3f6e8acd1d544ed1da91a0073e9d7021a00062829031a03ce59980481840b8201581c354cc2d68b7cb4ee4a87d714ab2a80e69ae1c8e07981835b6a9c1c51581c094dc39da2d8434f9ddb93749a1930288e5dd89ae04fa5914e157bd61a001e84800b582000000000000000000000000000000000000000000000000000000000000000000d81825820d6da036c1aeb7680323258c763a2a6e25be9b280c2a8fedd5e43cb89730fdadf011082581d603dce7844f36b23b8c3f90afba40aa188e7f1d3f6e8acd1d544ed1da91b000000025002c138111a004c4b401281825820d6da036c1aeb7680323258c763a2a6e25be9b280c2a8fedd5e43cb89730fdadf00a30081825820000000003dce7844f36b23b8c3f90afba40aa188e7f1d3f6e8acd1d544ed1da9584000f899d39b17fd5d66c192c4b50d343e42f7235b30504c8ae7619f93c828dc6dce4568dd69177c551828492d777a6727fd66c2fbccbda8c2aeed92032c99790a0581840200d87a808200000781591438591435010100332323232323232323232323232322259800991919191919191919191919192994c004c0040262646464b300100e8acc004c024c06cdd500744c9660020030158992cc004006264b300100180bc4c96600200315980098120014566002601a603e6ea800e264b300100180cc4c96600200301a80d406a0351323259800800c072264b300100180ec07603b01d899192cc00400603f13259800800c08204102081044c966002605a007159800980b18141baa00a8992cc00400604513259800800c08e047023811c4c8c9660020030258992cc00400604d026813409a26464b300100181444c966002003029814c0a605313259800981b001c4c8c8c8c8c8c94cc0d8cdcb24810d6368616c6c656e676549643a20003732660426ea40052201001325330373372c9201157369676e616c73206368616c6c656e676549643a2000373266044600260726ea80192201001325330383372c920114697320666f72206576616c756574696f6e3f3a2000598009811181c9baa3001303a375406314910474727565008a490566616c73650040dc2646464b3001302a303c37540031325980099b8748010c0f4dd5000c4c94cc0f4cdcb249095a6b446174756d3a2000373266050002910100159800800c5660026058607c6ea8006264b300100181cc4c96600200303a81d40ea0751323259800800c0f2264b300100181ec0f607b03d899192cc00400607f13259800800c5660026096005159800981a18231baa0018992cc00400608313259800800c10a08504282144c8c9660020030448992cc00400608b045822c11626464b3001001823c4c96600200304882441220911323259800800c12a264b3001001825c12e09704b899192cc00400609b13259800800c13a09d13259800982d001c4c8cc00400400888c96600200515330573372c9201117665726966696564207573657249643a20003732660846ea406122010015330573372c9201087573657249643a2000373266084603c60b26ea809922010015980099b8f018375c603c60b26ea809a2a660ae66e592410f766572696669656420686173683a20003732660846ea405522010015330573372c920106686173683a2000373266084604060b26ea809922010015980099b8f015375c604060b26ea809a2646464b30013049305b375400313232598009825982e9baa001899191919192cc004c140c188dd500144c94cc188cdcb24811175736572496420286e756d626572293a200037326609a6ea002122010015330623372c9201127077644861736820286e756d626572293a200037326609a6ea001922010015330623372c9201146368616c6c656e676520286e756d626572293a200037326609a6ea000522010015330623372c92010a6f766572666c6f773a200037326609a6ea000922010015980099919119bc6337886eecdd7181618339baa03337846eb8c0bcc19cdd501999bc53378a66f10ddd9bae302c306737540426f08dd7181798339baa0213378864b30010018a998332491077726f6e6720766b5f69632073697a6500168994c004c1b400a00737760028020dd71835800a0d2375860d460d660d660d660d660ce6ea8084de11bae302e3067375404266f10ddd9bae302e306737540666f08dd7183518359835983598339baa0213001001222259800801c400626464b30010048b46600200d00198370024cddb00199bb8375a60da0086eec00900620d6306d004375c60d60068348cc198dd4004198331ba8006330663750002660cc6ea0020cc198dd4000998331ba80064bd704528c54cc1892401267a6b5f7665726966792870726f6f662c207075626c69632c207a6b657929203f2046616c73650014a08308dd6983318319baa0028a99830a49b86578706563742028536f6d65286368616c6c656e6765292c206f766572666c6f7729203d0a2020202020207768656e207363616c61722e6e6577286e756d4368616c6c656e676529206973207b0a20202020202020204e6f6e65202d3e20287363616c61722e6e6577286d6f645f696e7465676572286e756d4368616c6c656e67652c207363616c61722e6669656c645f7072696d6529292c2031290a20202020202020206e202d3e20286e2c2030290a2020202020207d001641806eb4c194c198008c190004c966002609260c06ea80062660c6601066e180092082808080e0fffffffffbdfe5ffbf81a4fbceaa80bbe88488b0e79983a9dfcea9a69dedbe0e330634c10101004bd7044cc18c004cc18d30010100004bd7020bc300700133794944dd71813982f9baa02c375a60c260bc6ea80062a660b892014265787065637420536f6d65286861736829203d207363616c61722e66726f6d5f6279746561727261795f6269675f656e6469616e287369676e616c732e68617368290016416c60066eb8c090c174dd50151bad305f305c3754003153305a49014665787065637420536f6d652875736572496429203d207363616c61722e66726f6d5f6279746561727261795f6269675f656e6469616e287369676e616c732e757365724964290016416460026eb8c080c16cdd50141180119bca4a20024b30015980099b8948000006266e200052082808080e0fffffffffbdfe5ffbf81a4fbceaa80bbe88488b0e79983a9dfcea9a69dedbe0e8a50415d130243305c375000297ae08a60103d87a8000415d15330574912365787065637420766572696669656448617368203d3d207369676e616c732e6861736800164159153305749127657870656374207665726966696564557365724964203d3d207369676e616c732e7573657249640016415913259800800c14e0a7053829c4c8c00cc17c010dd7000a0be305c0024168600400504f415c6eb000609d04e416860ae00282a8c15c00cdd7000a0ae3054001414860a80066eb80050541828800a09e3051003375c0028288c13800504c18270019bae001413860960028248c11cdd5000c1010444101048410208104082020983049001411c60920066eb80050491823000a0883046003375c0028230c10c005041181f9baa00181c207881c40e207103841106082607c6ea80062a6607892012765787065637420496e6c696e65446174756d286461746129203d206f75747075742e646174756d001640ec6008607a6ea8c100c104c0f4dd51820181e9baa0018a9981da497565787065637420536f6d65286163636f756e74496e70757429203d0a2020202020207265666572656e63655f696e707574730a20202020202020207c3e2066696e645f6163636f756e745f696e70757428706172616d732e706f6c6963795f69642c20706172616d732e61737365745f6e616d6529001640e86644646600200201444b30010018a60103d87a8000899192cc004c0a8c966002605660846ea80062900044dd6982318219baa001410064b3001302b3042375400314c103d87a8000899198008009bab30473044375400444b30010018a6103d87a80008991919192cc004cdc8806001456600266e3c03000a26026660966ea00052f5c114c0103d87a8000411913300600600341186eb4c12000cdd7182300118250011824000a08c410064660020026eacc118c11cc10cdd51823182398219baa0032259800800c530103d87a80008991919192cc004cdc8806001456600266e3c03000a26024660946e980052f5c114c0103d87a8000411513300600600341146eacc11c00cdd7182280118248011823800a08a898061982200125eb8226600800800281f8c114008c10c0050411bae3001303c37540666eb8c010c0f0dd50199181f800a994c004c08cc0e8dd51801181d9baa0328acc00566002600200914a313001375c600660766ea802103845268a9981ca49596578706563740a20202020202020207369676e616c732e6368616c6c656e6765203d3d206368616c6c656e67654964207c7c207369676e616c732e6368616c6c656e6765203d3d207369676e616c732e6368616c6c656e6765001640e1159800980080245268a9981ca48127657870656374207369676e616c732e6368616c6c656e6765203d3d206368616c6c656e67654964001640e081c0dc79bae3002303a375400e4607a607c607c00246078607a00264646e50004dd9800991919191919191804198201ba7300537586082006660806e9cc014dd61820802198201ba798009bac3041002a5eb82446464646608a601a6608a608c0066608a6ea4c030dd59823001198229ba93232598009819000c5221008acc004c0b400626eb8c120c114dd500144c8c8dca0009bb3001304830453754004821104218219baa001304600133045304630470014bd700021823000982280098201baa0024018660806ea4c01cdd598208009982018209821000a5eb80c104c104004c100004c0fc004c0e8dd501714c00400697ae0911981f181f981e1baa0020014008444646600200200844b3001001880244cc00cc100004cc008008c10400503e11bb3374c0026e952000375860706072606a6ea80a4c0dcc0e0008c0d8004c0c8dd501240a90331bae00140d860660028188c0cc00cdd7000a066303000140b860600066eb80050301816800a05630293754015021409902140a86eb800502d1815000a050302a003375c0028150c09c00502518138019bae001409c60480028110c080dd5001c06101d4061021406203101880c204a30220014080604400501680b405a02c8118c08000501e180e1baa00e80a203280a40520290144084603c603e004603a00260326ea802a2b30013370e9003004c4c8c8c96600201d13232598009805800c566002603c6ea80422a005018407d1598009803000c566002603c6ea80422a005018407d15980099b87480100062b3001301e37540211500280c203e80c2036406c80d8c070dd50078992cc004c0280062b3001300a301c37540051323232598009804180f9baa0028992cc004c024c080dd5001454cc07ccdcb2490d73637269707420686173683a20003732660146ea400522010014a301c40786eb8c08cc080dd5001406d01d181118118011810800980e9baa00280c20348acc004c0140062b30013370e9003180e1baa002899191919192cc004c028c084dd5002454cc080cdcb2490d73637269707420686173683a2000373266016604a60446ea801122010015980099b87001482024bd00629462a6604092012b6465706f736974203d3d207374616b65526567697374726174696f6e4465706f736974203f2046616c73650014a080fa03c80f8dd698121812801181180098118011810800980e9baa00280ca0348a9980da491a496e636f7272656374205075626c6973682052656465656d65720016406880d0c06cdd5007405a02d01680b2042301e301f002375a603a00260326ea802a2c80b10161b8748008c004004889660026e29221022c20008998029bad0020018991919b8a488102682700001329800800ccdc01b8d0024800666e2922010127000034004444b3001337100049000440062646465300100699b800054800666e2ccdc00012cc004cdc40012402914818229037203a3371666e000056600266e2000520148a40c11481b901d002200c3370c004901019b8300148080cdc70020012034375c00494c00400e26464646464646601800400266e2922010128000025980099b880034803a266e0120f2010038acc004cdc4001a41000513370066e01208014003480362c80d901b2cc004006266e292201035b5d2900005899b8a489035b5f20009800800ccdc52441025d2900005914c00402600530060014025229800804c00a0028049008203c375860380046eb4c068004c8cdd81ba8301a001374e60360026ea800e264b3001001899b8a4881027b7d00003899b8a489037b5f20003232330010010032259800800c400e2b300130220018994c004026603c003337149101023a20009800804cc07c00600880490091810800c4ca6002013301e00199b8a489023a20009800804cc07c006600c66006006604600480490091810800a03e407c66e2922102207d0000340706eac00e264b3001001899b8a489025b5d00003899b8a489035b5f20009800800ccdc52441015d00003914c00401e0053004001401d229800803c00a00280390062038375800680f84444646600200200a44b30010018802c566002603e003133003301e001005899802180f00099801001180f800a038407044646600200200644b30013005001899b8a4890130000038acc004cdc4000a40011337149101012d0033002002337029000000c4cc018cdc2000a402866e2ccdc019b85001480512060003405480a8dc3a40006002002444b3001337120049000440063300100399b840024805266e2ccdc019b85002480512060001400c8088c03cdd50009809180980118088009808801180780098059baa0018a4d153300949011856616c696461746f722072657475726e65642066616c7365001365640202a6600c92011272656465656d65723a2052656465656d6572001615330054914a657870656374205a6b446174756d207b207573657249643a2076657269666965645573657249642c20686173683a207665726966696564486173682c207a6b6579207d203d2064617461001615330044911972656465656d65723a205075626c69736852656465656d6572001615330034917865787065637420526567697374657243726564656e7469616c207b0a2020202020202020202063726564656e7469616c3a20536372697074287363726970745f68617368292c0a202020202020202020206465706f7369743a204e657665722c0a20202020202020207d203d2063657274696669636174650016153300249190657870656374205265676973746572416e6444656c656761746543726564656e7469616c207b0a2020202020202020202063726564656e7469616c3a20536372697074287363726970745f68617368292c0a2020202020202020202064656c65676174652c0a202020202020202020206465706f7369742c0a20202020202020207d203d20636572746966696361746500165734ae7155ceaab9e5573eae815d0aba2574898130d8799f581cb8a5e329b500a66376047165cdfce62c3ecf245fd81d101533f814224a466f6e74757323303030d87980ff0001f5f6", +}; \ No newline at end of file