UNPKG

@lucid-evolution/lucid

Version:

Next-generation transaction builder for highly scalable dApps on Cardano

1 lines 194 kB
{"version":3,"sources":["../src/index.ts","../src/core.ts","../src/lucid-evolution/utils.ts","../src/lucid-evolution/LucidEvolution.ts","../src/tx-builder/internal/Collect.ts","../src/Errors.ts","../src/tx-builder/internal/TxUtils.ts","../src/tx-builder/internal/Service.ts","../src/tx-builder/internal/Read.ts","../src/tx-builder/internal/Attach.ts","../src/tx-builder/internal/Pay.ts","../src/tx-builder/internal/Mint.ts","../src/tx-builder/internal/Interval.ts","../src/tx-builder/internal/Signer.ts","../src/tx-builder/internal/Stake.ts","../src/tx-builder/internal/Pool.ts","../src/tx-builder/internal/Governance.ts","../src/tx-builder/internal/Metadata.ts","../src/tx-builder/internal/CompleteTxBuilder.ts","../src/tx-sign-builder/TxSignBuilder.ts","../src/tx-sign-builder/internal/CompleteTxSigner.ts","../src/tx-submit/TxSubmit.ts","../src/tx-sign-builder/internal/Sign.ts","../src/tx-builder/TxBuilder.ts","../src/tx-builder/TxConfig.ts"],"sourcesContent":["export * from \"./lucid-evolution/index.js\";\nexport * from \"./tx-builder/index.js\";\nexport * from \"./tx-sign-builder/index.js\";\nexport * from \"./tx-submit/TxSubmit.js\";\nexport * from \"./Errors.js\";\nexport * from \"./core.js\";\nexport * from \"@lucid-evolution/core-types\";\nexport * from \"@lucid-evolution/core-utils\";\nexport * from \"@lucid-evolution/plutus\";\nexport * from \"@lucid-evolution/provider\";\nexport * from \"@lucid-evolution/sign_data\";\nexport * from \"@lucid-evolution/utils\";\nexport * from \"@lucid-evolution/wallet\";\n","import { Effect } from \"effect\";\n\nexport * as CML from \"@anastasia-labs/cardano-multiplatform-lib-nodejs\";\n\nexport const makeReturn = <A, E>(program: Effect.Effect<A, E>) => {\n return {\n unsafeRun: () => Effect.runPromise(program),\n safeRun: () => Effect.runPromise(Effect.either(program)),\n program: () => program,\n };\n};\n","import { Json, Provider, UTxO, Unit } from \"@lucid-evolution/core-types\";\nimport { fromUnit, toUnit } from \"@lucid-evolution/utils\";\nimport { Constr, Data } from \"@lucid-evolution/plutus\";\n\nexport const datumOf = async <T = Data>(\n provider: Provider,\n utxo: UTxO,\n type?: T,\n): Promise<T> => {\n if (!utxo.datum) {\n if (!utxo.datumHash) {\n throw new Error(\"This UTxO does not have a datum hash.\");\n }\n utxo.datum = await provider.getDatum(utxo.datumHash);\n }\n return Data.from<T>(utxo.datum, type);\n};\n\n/** Query CIP-0068 metadata for a specifc asset. */\nexport const metadataOf = async <T = Json>(\n provider: Provider,\n unit: Unit,\n): Promise<T> => {\n const { policyId, name, label } = fromUnit(unit);\n switch (label) {\n case 222:\n case 333:\n case 444: {\n const utxo = await provider.getUtxoByUnit(toUnit(policyId, name, 100));\n const metadata = (await datumOf(provider, utxo)) as Constr<Data>;\n return Data.toJson(metadata.fields[0]);\n }\n default:\n throw new Error(\"No variant matched.\");\n }\n};\n","import {\n Credential,\n Delegation,\n Network,\n OutRef,\n PrivateKey,\n ProtocolParameters,\n Provider,\n Transaction,\n TxHash,\n Unit,\n UnixTime,\n UTxO,\n Wallet,\n WalletApi,\n} from \"@lucid-evolution/core-types\";\nimport { CML } from \"../core.js\";\nimport { datumOf, metadataOf } from \"./utils.js\";\nimport {\n createCostModels,\n PROTOCOL_PARAMETERS_DEFAULT,\n unixTimeToSlot,\n} from \"@lucid-evolution/utils\";\nimport * as TxBuilder from \"../tx-builder/TxBuilder.js\";\nimport * as TxConfig from \"../tx-builder/TxConfig.js\";\nimport * as TxSignBuilder from \"../tx-sign-builder/TxSignBuilder.js\";\nimport { Data, SLOT_CONFIG_NETWORK } from \"@lucid-evolution/plutus\";\nimport {\n makeWalletFromAddress,\n makeWalletFromAPI,\n makeWalletFromPrivateKey,\n makeWalletFromSeed,\n} from \"@lucid-evolution/wallet\";\nimport { Emulator } from \"@lucid-evolution/provider\";\nimport { Effect, pipe, Data as _Data } from \"effect\";\nimport { NullableError, UnauthorizedNetwork } from \"../Errors.js\";\nimport { TimeoutExceptionTypeId } from \"effect/Cause\";\n\nexport type LucidEvolution = {\n config: () => Partial<LucidConfig>;\n wallet: () => Wallet;\n overrideUTxOs: (utxos: UTxO[]) => void;\n switchProvider: (provider: Provider) => Promise<void>;\n newTx: () => TxBuilder.TxBuilder;\n fromTx: (tx: Transaction) => TxSignBuilder.TxSignBuilder;\n selectWallet: {\n fromSeed: (\n seed: string,\n options?: {\n addressType?: \"Base\" | \"Enterprise\";\n accountIndex?: number;\n password?: string;\n },\n ) => void;\n fromPrivateKey: (privateKey: PrivateKey) => void;\n fromAPI: (walletAPI: WalletApi) => void;\n fromAddress: (address: string, utxos: UTxO[]) => void;\n };\n currentSlot: () => number;\n unixTimeToSlot: (unixTime: UnixTime) => number;\n utxosAt: (addressOrCredential: string | Credential) => Promise<UTxO[]>;\n utxosAtWithUnit: (\n addressOrCredential: string | Credential,\n unit: string,\n ) => Promise<UTxO[]>;\n utxoByUnit: (unit: string) => Promise<UTxO>;\n utxosByOutRef: (outRefs: OutRef[]) => Promise<UTxO[]>;\n delegationAt: (rewardAddress: string) => Promise<Delegation>;\n awaitTx: (\n txHash: string,\n checkInterval?: number | undefined,\n ) => Promise<boolean>;\n datumOf: <T extends Data>(utxo: UTxO, type?: T | undefined) => Promise<T>;\n metadataOf: <T = any>(unit: string) => Promise<T>;\n};\n\nexport type LucidConfig = {\n provider: Provider;\n network: Network;\n wallet: Wallet | undefined;\n txbuilderconfig: CML.TransactionBuilderConfig;\n costModels: CML.CostModels;\n protocolParameters: ProtocolParameters;\n};\n\ntype LucidOptions = {\n /**\n * Predefined protocol parameters to use instead of retrieving them from the provider.\n * If not specified, it will fetch the latest protocol parameters from the provider.\n */\n presetProtocolParameters?: ProtocolParameters;\n};\n\n//TODO: turn this to Effect\nexport const Lucid = async (\n provider?: Provider | undefined,\n network?: Network,\n options: LucidOptions = {},\n): Promise<LucidEvolution> => {\n const protocolParameters: ProtocolParameters | undefined =\n options.presetProtocolParameters ||\n (await provider?.getProtocolParameters());\n\n const costModels = protocolParameters\n ? createCostModels(protocolParameters.costModels)\n : undefined;\n const config: Partial<LucidConfig> = {\n provider: provider,\n network: network,\n wallet: undefined,\n costModels: costModels,\n txbuilderconfig:\n protocolParameters && costModels\n ? TxConfig.makeTxConfig(protocolParameters, costModels)\n : undefined,\n protocolParameters,\n };\n if (config.provider && \"slot\" in config.provider) {\n const emulator: Emulator = config.provider as Emulator;\n Effect.gen(function* () {\n const custom = yield* pipe(\n validateNotNullableNetwork(network),\n // Effect.filterOrFail(\n // (network) => network === \"Custom\",\n // () =>\n // new UnauthorizedNetwork({\n // message: `Expected Custom, received ${String(network)}`,\n // }),\n // ),\n );\n SLOT_CONFIG_NETWORK[custom] = {\n zeroTime: emulator.now(),\n zeroSlot: 0,\n slotLength: 1000,\n };\n }).pipe(Effect.runSync);\n }\n return {\n config: () => config,\n wallet: () => config.wallet as Wallet,\n overrideUTxOs: (utxos: UTxO[]) => config.wallet?.overrideUTxOs(utxos),\n switchProvider: async (provider: Provider) => {\n const protocolParam = await provider.getProtocolParameters();\n const costModels = createCostModels(protocolParam.costModels);\n config.provider = provider;\n config.costModels = costModels;\n config.txbuilderconfig = TxConfig.makeTxConfig(protocolParam, costModels);\n config.protocolParameters = protocolParam;\n },\n newTx: (): TxBuilder.TxBuilder =>\n Effect.gen(function* () {\n const provider = yield* Effect.fromNullable(config.provider);\n const network = yield* Effect.fromNullable(config.network);\n const costModels = yield* validateNotNullable(\n config.costModels,\n \"CostModels are not set in Lucid instance\",\n );\n const txbuilderconfig = yield* validateNotNullable(\n config.txbuilderconfig,\n \"txbuilderconfig is not set in Lucid instance\",\n );\n const protocolParameters = yield* validateNotNullable(\n config.protocolParameters,\n \"protocolParameters are not set in Lucid instance\",\n );\n return TxBuilder.makeTxBuilder({\n provider,\n network,\n wallet: config.wallet,\n costModels,\n txbuilderconfig,\n protocolParameters,\n });\n }).pipe(Effect.runSync),\n fromTx: (tx: Transaction) =>\n TxSignBuilder.makeTxSignBuilder(\n config.wallet,\n CML.Transaction.from_cbor_hex(tx),\n ),\n selectWallet: {\n fromSeed: (\n seed: string,\n options?: {\n addressType?: \"Base\" | \"Enterprise\";\n accountIndex?: number;\n password?: string;\n },\n ) =>\n Effect.gen(function* () {\n config.wallet = makeWalletFromSeed(\n yield* validateNotNullableProvider(config.provider),\n yield* validateNotNullableNetwork(network),\n seed,\n options,\n );\n }).pipe(Effect.runSync),\n fromPrivateKey: (privateKey: PrivateKey) =>\n Effect.gen(function* () {\n config.wallet = makeWalletFromPrivateKey(\n yield* validateNotNullableProvider(config.provider),\n yield* validateNotNullableNetwork(network),\n privateKey,\n );\n }).pipe(Effect.runSync),\n fromAPI: (walletAPI: WalletApi) =>\n Effect.gen(function* () {\n config.wallet = makeWalletFromAPI(\n yield* validateNotNullableProvider(config.provider),\n walletAPI,\n );\n }).pipe(Effect.runSync),\n fromAddress: (address: string, utxos: UTxO[]) =>\n Effect.gen(function* () {\n config.wallet = makeWalletFromAddress(\n yield* validateNotNullableProvider(config.provider),\n yield* validateNotNullableNetwork(network),\n address,\n utxos,\n );\n }).pipe(Effect.runSync),\n },\n currentSlot: () =>\n pipe(\n validateNotNullableNetwork(config.network),\n Effect.map((network) => unixTimeToSlot(network, Date.now())),\n Effect.runSync,\n ),\n unixTimeToSlot: (unixTime: UnixTime) =>\n pipe(\n validateNotNullableNetwork(config.network),\n Effect.map((network) => unixTimeToSlot(network, unixTime)),\n Effect.runSync,\n ),\n utxosAt: (addressOrCredential: string | Credential) =>\n pipe(\n validateNotNullableProvider(config.provider),\n Effect.flatMap((provider) =>\n Effect.promise(() => provider.getUtxos(addressOrCredential)),\n ),\n Effect.runPromise,\n ),\n utxosAtWithUnit: (addressOrCredential: string | Credential, unit: Unit) =>\n pipe(\n validateNotNullableProvider(config.provider),\n Effect.flatMap((provider) =>\n Effect.promise(() =>\n provider.getUtxosWithUnit(addressOrCredential, unit),\n ),\n ),\n Effect.runPromise,\n ),\n utxoByUnit: (unit: Unit) =>\n pipe(\n validateNotNullableProvider(config.provider),\n Effect.flatMap((provider) =>\n Effect.promise(() => provider.getUtxoByUnit(unit)),\n ),\n Effect.runPromise,\n ),\n utxosByOutRef: (outRefs: OutRef[]) =>\n pipe(\n validateNotNullableProvider(config.provider),\n Effect.flatMap((provider) =>\n Effect.promise(() => provider.getUtxosByOutRef(outRefs)),\n ),\n Effect.runPromise,\n ),\n delegationAt: (rewardAddress: string) =>\n pipe(\n validateNotNullableProvider(config.provider),\n Effect.flatMap((provider) =>\n Effect.promise(() => provider.getDelegation(rewardAddress)),\n ),\n Effect.runPromise,\n ),\n awaitTx: (txHash: TxHash, checkInterval?: number) =>\n pipe(\n validateNotNullableProvider(config.provider),\n Effect.flatMap((provider) =>\n Effect.promise(() => provider.awaitTx(txHash, checkInterval)),\n ),\n Effect.runPromise,\n ),\n datumOf: <T extends Data>(utxo: UTxO, type?: T | undefined) =>\n pipe(\n validateNotNullableProvider(config.provider),\n Effect.flatMap((provider) =>\n Effect.promise(() => datumOf(provider, utxo, type)),\n ),\n Effect.runPromise,\n ),\n metadataOf: (unit: string) =>\n pipe(\n validateNotNullableProvider(config.provider),\n Effect.flatMap((provider) =>\n Effect.promise(() => metadataOf(provider, unit)),\n ),\n Effect.runPromise,\n ),\n };\n};\n\nconst validateNotNullable = <T>(value: T | undefined, message: string) =>\n pipe(\n Effect.fromNullable(value),\n Effect.orElseFail(() => new NullableError({ message })),\n );\n\nconst validateNotNullableNetwork = (network: Network | undefined) =>\n validateNotNullable(network, \"Network is not set in Lucid instance\");\nconst validateNotNullableProvider = (provider: Provider | undefined) =>\n validateNotNullable(provider, \"Provider is not set in Lucid instance\");\n","import { Effect, pipe } from \"effect\";\nimport { Data } from \"@lucid-evolution/plutus\";\nimport { utxoToCore } from \"@lucid-evolution/utils\";\nimport { Redeemer, RedeemerBuilder, UTxO } from \"@lucid-evolution/core-types\";\nimport { ERROR_MESSAGE, TxBuilderError } from \"../../Errors.js\";\nimport * as CML from \"@anastasia-labs/cardano-multiplatform-lib-nodejs\";\nimport { resolveDatum, toPartial, toV1, toV2, toV3 } from \"./TxUtils.js\";\nimport { paymentCredentialOf } from \"@lucid-evolution/utils\";\nimport { datumOf } from \"../../lucid-evolution/utils.js\";\nimport { TxConfig } from \"./Service.js\";\n\nexport const collectError = (cause: unknown) =>\n new TxBuilderError({ cause: `{ Collect: ${cause} }` });\n\nexport const collectFromUTxO =\n (utxos: UTxO[], collectInputs: Boolean = true) =>\n (redeemer?: Redeemer) =>\n Effect.gen(function* () {\n const { config } = yield* TxConfig;\n if (utxos.length === 0) yield* collectError(ERROR_MESSAGE.EMPTY_UTXO);\n for (const utxo of utxos) {\n // fetch the datum when the datumHash is present\n const resolvedDatum = yield* resolveDatum(\n utxo.datumHash,\n utxo.datum,\n config.lucidConfig.provider,\n );\n utxo.datum = resolvedDatum;\n // Skip adding UTxO to collectedInputs when building redeemers to prevent duplicate inputs\n // Store inputs for later use in the txBuilder\n if (collectInputs) config.collectedInputs.push(utxo);\n //TODO: Add config.collectedAssets\n const input = CML.SingleInputBuilder.from_transaction_unspent_output(\n utxoToCore({ ...utxo, datum: resolvedDatum }),\n );\n const credential = paymentCredentialOf(utxo.address);\n\n if (credential.type == \"Script\") {\n const script = yield* pipe(\n Effect.fromNullable(config.scripts.get(credential.hash)),\n Effect.orElseFail(() =>\n collectError(\n collectError(ERROR_MESSAGE.MISSING_SCRIPT(credential.hash)),\n ),\n ),\n );\n switch (script.type) {\n case \"Native\":\n config.txBuilder.add_input(\n input.native_script(\n CML.NativeScript.from_cbor_hex(script.script),\n CML.NativeScriptWitnessInfo.assume_signature_count(),\n ),\n );\n break;\n case \"PlutusV1\": {\n const red = yield* pipe(\n Effect.fromNullable(redeemer),\n Effect.orElseFail(() =>\n collectError(ERROR_MESSAGE.MISSING_REDEEMER),\n ),\n );\n config.txBuilder.add_input(\n input.plutus_script(\n toPartial(toV1(script.script), red),\n CML.Ed25519KeyHashList.new(),\n CML.PlutusData.from_cbor_hex(utxo.datum!),\n ),\n );\n break;\n }\n case \"PlutusV2\": {\n const v2 = toV2(script.script);\n const red = yield* pipe(\n Effect.fromNullable(redeemer),\n Effect.orElseFail(() =>\n collectError(ERROR_MESSAGE.MISSING_REDEEMER),\n ),\n );\n const partial = toPartial(v2, red);\n config.txBuilder.add_input(\n utxo.datum && utxo.datumHash\n ? input.plutus_script(\n partial,\n CML.Ed25519KeyHashList.new(),\n CML.PlutusData.from_cbor_hex(utxo.datum),\n )\n : input.plutus_script_inline_datum(\n partial,\n CML.Ed25519KeyHashList.new(),\n ),\n );\n break;\n }\n case \"PlutusV3\": {\n const v3 = toV3(script.script);\n const red = yield* pipe(\n Effect.fromNullable(redeemer),\n Effect.orElseFail(() =>\n collectError(ERROR_MESSAGE.MISSING_REDEEMER),\n ),\n );\n const partial = toPartial(v3, red);\n config.txBuilder.add_input(\n utxo.datum && utxo.datumHash\n ? input.plutus_script(\n partial,\n CML.Ed25519KeyHashList.new(),\n CML.PlutusData.from_cbor_hex(utxo.datum),\n )\n : input.plutus_script_inline_datum(\n partial,\n CML.Ed25519KeyHashList.new(),\n ),\n );\n break;\n }\n }\n } else {\n config.txBuilder.add_input(input.payment_key());\n }\n }\n });\n\n/* \"collectFrom\" for RedeemerBuilder needs similar utxo validations as done for Redeemer.\n These should happen before coin selection; so the effect this function returns is added\n to the \"programs\".\n*/\nexport const collectFromUTxOPartial = (\n utxos: UTxO[],\n redeemerBuilder: RedeemerBuilder,\n) =>\n Effect.gen(function* () {\n const { config } = yield* TxConfig;\n if (utxos.length === 0) yield* collectError(ERROR_MESSAGE.EMPTY_UTXO);\n if (redeemerBuilder.kind === \"self\") redeemerBuilder.inputs = utxos;\n for (const utxo of utxos) {\n if (utxo.datumHash && !utxo.datum) {\n const data = yield* Effect.tryPromise({\n try: () => datumOf(config.lucidConfig.provider, utxo),\n catch: (cause) => collectError({ cause }),\n });\n utxo.datum = Data.to(data);\n }\n // An array of unspent transaction outputs to be used as inputs when running uplc eval.\n config.collectedInputs.push(utxo);\n //TODO: Add config.collectedAssets\n }\n // NOTE: If RedeemerBuilder is of kind \"self\" the partial program will be incorrect\n // however it won't matter as it won't be used if that's the case. But we still need\n // that RedeemerBuilder in partialPrograms to construct it later during \"complete\"\n const partialProgram = collectFromUTxO(utxos, false);\n config.partialPrograms.set(redeemerBuilder, partialProgram);\n });\n","import { Network } from \"@lucid-evolution/core-types\";\nimport { Data } from \"effect\";\n\nexport const ERROR_MESSAGE = {\n MULTIPLE_POLICIES:\n \"MULTIPLE_POLICIES: Only one policy id allowed. You can chain multiple mintAssets functions together if you need to mint assets with different policy ids. \",\n EMPTY_UTXO:\n \"EMPTY_UTXO: UTxO array is empty. If a Tx has been recently submitted, consider waiting for chain sync\",\n MISSING_WALLET:\n \"MISSING_WALLET: please ensure that your wallet has been properly configured and initialized\",\n MISSING_REDEEMER: \"MISSING_REDEEMER: redeemer can not be undefined\",\n DATUM_NOT_SET:\n \"DATUM_NOT_SET: Script inputs becomes unspendable without datum.\",\n EMPTY_ASSETS:\n \"EMPTY_ASSETS: Attempting to pay to an address with an empty assets object\",\n MISSING_REWARD_TYPE: \"MISSING_REWARD_TYPE: Address type must be Reward type.\",\n MISSING_STAKE_CREDENTIAL:\n \"MISSING_STAKE_CREDENTIAL: Address does not contain stake credential\",\n MISSING_PAYMENT_CREDENTIAL:\n \"MISSING_PAYMENT_CREDENTIAL: Address does not contain payment credential\",\n INVALID_METADATA: \"INVALID_METADATA: metadata is invalid\",\n SCRIPT_CREDENTIAL_NOT_ALLOWED:\n \"SCRIPT_CREDENTIAL_NOT_ALLOWED: Only verification key credential is allowed\",\n INVALID_SCRIPT: \"INVALID_SCRIPT: Script is invalid\",\n EXPECTED_KEY_HASH: \"EXPECTED_KEY_HASH\",\n INVALID_NETWORK: (\n address: string,\n actualNetworkId: number,\n network: Network,\n ) =>\n `Invalid address: ${address}, Expected address with network id ${actualNetworkId}, current network ${network}`,\n MISSING_SCRIPT: (hash: string) =>\n `MISSING_SCRIPT: Script not found when building transaction, consider using attach modules. script_hash: ${hash}`,\n MISSING_POLICY: (policyId: string) =>\n `MISSING_POLICY: No policy found, policy_id: ${policyId}`,\n} as const;\n\nexport class NullableError extends Data.TaggedError(\"NullableError\")<{\n readonly message: string;\n}> {}\n\nexport class UnauthorizedNetwork extends Data.TaggedError(\n \"UnauthorizedNetwork\",\n)<{\n readonly message: string;\n}> {}\n\nexport class TxBuilderError extends Data.TaggedError(\"TxBuilderError\")<{\n readonly cause: unknown;\n}> {\n get message() {\n return `${this.cause}`;\n }\n}\nexport type TransactionError = RunTimeError | TxBuilderError;\n\nexport class TxSignerError extends Data.TaggedError(\"TxSignerError\")<{\n readonly cause: unknown;\n}> {\n get message() {\n return `${this.cause}`;\n }\n}\n\nexport type TransactionSignError = RunTimeError | TxSignerError;\n\nexport class TxSubmitError extends Data.TaggedError(\"TxSubmitError\")<{\n readonly cause: unknown;\n}> {\n get message() {\n return `${this.cause}`;\n }\n}\n\n//NOTE: RunTimeError is used to catch all unexpected errors primarly from CML library\nexport class RunTimeError extends Data.TaggedError(\"RunTimeError\")<{\n cause: unknown;\n}> {\n get message() {\n return `${this.cause}`;\n }\n}\n","import * as CML from \"@anastasia-labs/cardano-multiplatform-lib-nodejs\";\nimport { CBORHex } from \"../types.js\";\nimport { Effect, pipe } from \"effect\";\nimport { networkToId, getAddressDetails } from \"@lucid-evolution/utils\";\nimport {\n Address,\n AddressDetails,\n Redeemer,\n RedeemerBuilder,\n RewardAddress,\n Credential,\n UTxO,\n Provider,\n} from \"@lucid-evolution/core-types\";\nimport { ERROR_MESSAGE, TxBuilderError } from \"../../Errors.js\";\nimport { LucidConfig } from \"../../lucid-evolution/LucidEvolution.js\";\nimport { TxBuilderConfig } from \"../TxBuilder.js\";\n\nimport * as TxBuilder from \"../TxBuilder.js\";\nimport { TxConfig } from \"./Service.js\";\nimport { Data } from \"@lucid-evolution/plutus\";\n\nexport const txBuilderError = (cause: unknown) =>\n new TxBuilderError({ cause: `{ TxBuilderError : ${cause} }` });\n\n//TODO: improve error message, utils is used in different modules\nexport const toCMLAddress = (\n address: Address | RewardAddress,\n lucidConfig: LucidConfig,\n): Effect.Effect<CML.Address, TxBuilderError, never> =>\n Effect.gen(function* ($) {\n const { type } = yield* validateAddressDetails(address, lucidConfig);\n return type === \"Byron\"\n ? CML.ByronAddress.from_base58(address).to_address()\n : CML.Address.from_bech32(address);\n });\n\nexport const toV1 = (script: string) =>\n CML.PlutusScript.from_v1(CML.PlutusV1Script.from_cbor_hex(script));\n\nexport const toV2 = (script: string) =>\n CML.PlutusScript.from_v2(CML.PlutusV2Script.from_cbor_hex(script));\n\nexport const toV3 = (script: string) =>\n CML.PlutusScript.from_v3(CML.PlutusV3Script.from_cbor_hex(script));\n\nexport const toPartial = (script: CML.PlutusScript, redeemer: CBORHex) =>\n CML.PartialPlutusWitness.new(\n CML.PlutusScriptWitness.new_script(script),\n CML.PlutusData.from_cbor_hex(redeemer),\n );\n\nexport const handleRedeemerBuilder = (\n config: TxBuilderConfig,\n partialProgram: (\n redeemer?: string | undefined,\n ) => Effect.Effect<void, TxBuilderError, TxConfig>,\n redeemer?: string | RedeemerBuilder,\n) => {\n if (typeof redeemer === \"object\") {\n config.partialPrograms.set(redeemer, partialProgram);\n } else {\n const program = partialProgram(redeemer);\n config.programs.push(program);\n }\n};\n\n//NOTE: deprecated\n// export function toCMLTransactionHash(body: CML.TransactionBody) {\n// const TransactionHash = C.hash_transaction(\n// C.TransactionBody.from_bytes(fromHex(body.to_cbor_hex())),\n// );\n// return CML.TransactionHash.from_hex(TransactionHash.to_hex());\n// }\n\nexport function isEqual(arr1: Uint8Array, arr2: Uint8Array): boolean {\n if (arr1.length !== arr2.length) {\n return false;\n }\n return arr1.every((value, index) => value === arr2[index]);\n}\n\nexport const validateAddressDetails = (\n address: Address | RewardAddress,\n lucidConfig: LucidConfig,\n): Effect.Effect<AddressDetails, TxBuilderError, never> =>\n Effect.gen(function* ($) {\n const addressDetails = yield* $(\n Effect.try({\n try: () => getAddressDetails(address),\n catch: (cause) =>\n new TxBuilderError({\n cause,\n }),\n }),\n );\n const actualNetworkId = networkToId(lucidConfig.network);\n if (addressDetails.networkId !== actualNetworkId)\n yield* new TxBuilderError({\n cause: ERROR_MESSAGE.INVALID_NETWORK(\n address,\n actualNetworkId,\n lucidConfig.network,\n ),\n });\n\n return addressDetails;\n });\n\nexport const processCertificate = (\n stakeCredential: Credential,\n config: TxBuilder.TxBuilderConfig,\n buildCert: (credential: CML.Credential) => CML.SingleCertificateBuilder,\n redeemer?: Redeemer,\n): Effect.Effect<void, TxBuilderError> =>\n Effect.gen(function* () {\n switch (stakeCredential.type) {\n case \"Key\": {\n const credential = CML.Credential.new_pub_key(\n CML.Ed25519KeyHash.from_hex(stakeCredential.hash),\n );\n const certBuilder = buildCert(credential);\n config.txBuilder.add_cert(certBuilder.payment_key());\n break;\n }\n\n case \"Script\": {\n const credential = CML.Credential.new_script(\n CML.ScriptHash.from_hex(stakeCredential.hash),\n );\n const certBuilder = buildCert(credential);\n\n const script = yield* pipe(\n Effect.fromNullable(config.scripts.get(stakeCredential.hash)),\n Effect.orElseFail(() =>\n txBuilderError(ERROR_MESSAGE.MISSING_SCRIPT(stakeCredential.hash)),\n ),\n );\n\n const addPlutusCertificate = (\n scriptVersion: CML.PlutusScript,\n ): Effect.Effect<void, TxBuilderError> => {\n return Effect.gen(function* () {\n const red = yield* pipe(\n Effect.fromNullable(redeemer),\n Effect.orElseFail(() =>\n txBuilderError(ERROR_MESSAGE.MISSING_REDEEMER),\n ),\n );\n config.txBuilder.add_cert(\n certBuilder.plutus_script(\n toPartial(scriptVersion, red),\n CML.Ed25519KeyHashList.new(),\n ),\n );\n });\n };\n\n switch (script.type) {\n case \"PlutusV1\":\n yield* addPlutusCertificate(toV1(script.script));\n break;\n\n case \"PlutusV2\":\n yield* addPlutusCertificate(toV2(script.script));\n break;\n case \"PlutusV3\":\n yield* addPlutusCertificate(toV3(script.script));\n break;\n\n case \"Native\":\n config.txBuilder.add_cert(\n certBuilder.native_script(\n CML.NativeScript.from_cbor_hex(script.script),\n CML.NativeScriptWitnessInfo.assume_signature_count(),\n ),\n );\n break;\n }\n break;\n }\n }\n });\n\nexport const validateAndGetStakeCredential = (\n rewardAddress: RewardAddress,\n config: TxBuilder.TxBuilderConfig,\n): Effect.Effect<Credential, TxBuilderError> =>\n Effect.gen(function* () {\n const addressDetails = yield* pipe(\n validateAddressDetails(rewardAddress, config.lucidConfig),\n Effect.andThen((address) =>\n address.type !== \"Reward\"\n ? txBuilderError(ERROR_MESSAGE.MISSING_REWARD_TYPE)\n : Effect.succeed(address),\n ),\n );\n\n const stakeCredential = yield* pipe(\n Effect.fromNullable(addressDetails.stakeCredential),\n Effect.orElseFail(() =>\n txBuilderError(ERROR_MESSAGE.MISSING_STAKE_CREDENTIAL),\n ),\n );\n\n return stakeCredential;\n });\n\nexport const resolveDatum = (\n datumHash: UTxO[\"datumHash\"],\n datum: UTxO[\"datum\"],\n provider: Provider,\n) =>\n Effect.gen(function* () {\n // Only fetch the datum if the datumHash is present and the datum is not present.\n if (!datumHash || datum) return datum;\n return yield* Effect.tryPromise({\n try: () => provider.getDatum(datumHash),\n catch: txBuilderError,\n });\n });\n","import { Context, Effect } from \"effect\";\nimport { TxBuilderConfig } from \"../TxBuilder.js\";\n\nexport class TxConfig extends Context.Tag(\"TxConfig\")<\n TxConfig,\n {\n readonly config: TxBuilderConfig;\n }\n>() {}\n","import { Effect } from \"effect\";\nimport { utxoToCore } from \"@lucid-evolution/utils\";\nimport { UTxO } from \"@lucid-evolution/core-types\";\nimport { ERROR_MESSAGE, TxBuilderError } from \"../../Errors.js\";\nimport { resolveDatum } from \"./TxUtils.js\";\nimport { TxConfig } from \"./Service.js\";\n\nexport const readError = (cause: unknown) =>\n new TxBuilderError({ cause: `{ Read : ${cause} }` });\n\nexport const readFrom = (utxos: UTxO[]) =>\n Effect.gen(function* () {\n const { config } = yield* TxConfig;\n if (utxos.length === 0) yield* readError(ERROR_MESSAGE.EMPTY_UTXO);\n for (const utxo of utxos) {\n // fetch the datum when the datumHash is present\n const resolvedDatum = yield* resolveDatum(\n utxo.datumHash,\n utxo.datum,\n config.lucidConfig.provider,\n );\n\n const coreUtxo = utxoToCore({ ...utxo, datum: resolvedDatum });\n const exists = config.readInputs.some(\n (input) =>\n input.txHash === utxo.txHash &&\n input.outputIndex === utxo.outputIndex,\n );\n\n if (!exists) {\n config.txBuilder.add_reference_input(coreUtxo);\n // Store inputs for later use in the txBuilder\n config.readInputs.push(utxo);\n }\n }\n });\n","import { applyDoubleCborEncoding } from \"@lucid-evolution/utils\";\nimport {\n CertificateValidator,\n MintingPolicy,\n ProposeValidator,\n SpendingValidator,\n Validator,\n VoteValidator,\n WithdrawalValidator,\n} from \"@lucid-evolution/core-types\";\nimport { CML } from \"../../core.js\";\n\nexport const attachScript = ({ type, script }: Validator) => {\n //TODO: script should be a branded type\n switch (type) {\n case \"Native\":\n return {\n key: CML.NativeScript.from_cbor_hex(script).hash().to_hex(),\n value: { type, script },\n };\n case \"PlutusV1\":\n return {\n key: CML.PlutusV1Script.from_cbor_hex(applyDoubleCborEncoding(script))\n .hash()\n .to_hex(),\n value: { type, script: applyDoubleCborEncoding(script) },\n };\n case \"PlutusV2\":\n return {\n key: CML.PlutusV2Script.from_cbor_hex(applyDoubleCborEncoding(script))\n .hash()\n .to_hex(),\n value: { type, script: applyDoubleCborEncoding(script) },\n };\n case \"PlutusV3\":\n return {\n key: CML.PlutusV3Script.from_cbor_hex(applyDoubleCborEncoding(script))\n .hash()\n .to_hex(),\n value: { type, script: applyDoubleCborEncoding(script) },\n };\n default:\n throw new Error(`Exhaustive check failed: Unhandled case ${type}`);\n }\n};\nexport const attachSpendingValidator = (spendingValidator: SpendingValidator) =>\n attachScript(spendingValidator);\n\nexport const attachMintingPolicy = (mintingPolicy: MintingPolicy) =>\n attachScript(mintingPolicy);\n\nexport const attachCertificateValidator = (\n certValidator: CertificateValidator,\n) => attachScript(certValidator);\n\nexport const attachWithdrawalValidator = (\n withdrawalValidator: WithdrawalValidator,\n) => attachScript(withdrawalValidator);\n\nexport const attachVoteValidator = (voteValidator: VoteValidator) =>\n attachScript(voteValidator);\n\nexport const attachProposeValidator = (proposeValidator: ProposeValidator) =>\n attachScript(proposeValidator);\n","import { Effect, Scope } from \"effect\";\nimport {\n addAssets,\n assetsToValue,\n coreToTxOutput,\n toScriptRef,\n valueToAssets,\n} from \"@lucid-evolution/utils\";\nimport { Address, Assets, Script } from \"@lucid-evolution/core-types\";\nimport { OutputDatum } from \"../types.js\";\nimport * as TxBuilder from \"../TxBuilder.js\";\nimport { CML } from \"../../core.js\";\nimport { toCMLAddress } from \"./TxUtils.js\";\nimport { ERROR_MESSAGE, TxBuilderError } from \"../../Errors.js\";\nimport { TxConfig } from \"./Service.js\";\n\nexport const payError = (cause: unknown) =>\n new TxBuilderError({ cause: `{ Pay: ${cause} }` });\n\n/** Pay to a public key or native script address. */\nexport const payToAddress = (\n // config: TxBuilder.TxBuilderConfig,\n address: Address,\n assets: Assets,\n) =>\n Effect.gen(function* () {\n const { config } = yield* TxConfig;\n const outputBuilder = CML.TransactionOutputBuilder.new()\n .with_address(yield* toCMLAddress(address, config.lucidConfig))\n .next();\n\n if (Object.keys(assets).length == 0)\n yield* payError(ERROR_MESSAGE.EMPTY_ASSETS);\n\n const value = assetsToValue(assets);\n let outputResult = outputBuilder\n .with_asset_and_min_required_coin(\n value.multi_asset(),\n config.lucidConfig.protocolParameters.coinsPerUtxoByte,\n )\n .build();\n\n const setLovelaces = assets[\"lovelace\"];\n if (setLovelaces) {\n const minLovelace = outputResult.output().amount().coin();\n if (setLovelaces > minLovelace) {\n outputResult = outputBuilder.with_value(value).build();\n }\n }\n // Keep track of actual total output value\n config.totalOutputAssets = addAssets(\n config.totalOutputAssets,\n valueToAssets(outputResult.output().amount()),\n );\n config.payToOutputs = [\n ...config.payToOutputs,\n coreToTxOutput(outputResult.output()),\n ];\n config.txBuilder.add_output(outputResult);\n });\n\n/** Pay to a public key or native script address with datum or scriptRef. */\nexport const ToAddressWithData = (\n address: Address,\n outputDatum?: OutputDatum,\n assets?: Assets,\n scriptRef?: Script,\n) =>\n Effect.gen(function* () {\n const { config } = yield* TxConfig;\n //TODO: Test with datumhash\n const outputBuilder = buildBaseOutput(address, outputDatum, scriptRef);\n\n assets ??= {};\n const value = assetsToValue(assets);\n let outputResult = outputBuilder\n .with_asset_and_min_required_coin(\n value.multi_asset(),\n config.lucidConfig.protocolParameters.coinsPerUtxoByte,\n )\n .build();\n\n const setLovelaces = assets[\"lovelace\"];\n if (setLovelaces) {\n const minLovelace = outputResult.output().amount().coin();\n if (setLovelaces > minLovelace) {\n outputResult = outputBuilder.with_value(value).build();\n }\n }\n // Keep track of actual total output value\n config.totalOutputAssets = addAssets(\n config.totalOutputAssets,\n valueToAssets(outputResult.output().amount()),\n );\n config.payToOutputs = [\n ...config.payToOutputs,\n coreToTxOutput(outputResult.output()),\n ];\n config.txBuilder.add_output(outputResult);\n });\n\n/** Pay to a plutus script address with datum or scriptRef. */\nexport const ToContract = (\n address: Address,\n outputDatum?: OutputDatum,\n assets?: Assets,\n scriptRef?: Script,\n) => ToAddressWithData(address, outputDatum, assets, scriptRef);\n\nexport const buildBaseOutput = (\n address: Address,\n outputDatum?: OutputDatum,\n scriptRef?: Script,\n) => {\n let baseBuilder: CML.TransactionOutputBuilder;\n const addressBuilder = CML.TransactionOutputBuilder.new().with_address(\n CML.Address.from_bech32(address),\n );\n if (outputDatum) {\n if (outputDatum.value.trim() === \"\") {\n throw new Error(\n \"datum value is missing. Please provide a non-empty cbor hex data.\",\n );\n }\n switch (outputDatum.kind) {\n case \"hash\": {\n const datumOption = CML.DatumOption.new_hash(\n CML.DatumHash.from_hex(outputDatum.value),\n );\n baseBuilder = addressBuilder.with_data(datumOption);\n break;\n }\n case \"asHash\": {\n const plutusData = CML.PlutusData.from_cbor_hex(outputDatum.value);\n baseBuilder = addressBuilder.with_communication_data(plutusData);\n break;\n }\n case \"inline\": {\n const plutusData = CML.PlutusData.from_cbor_hex(outputDatum.value);\n const datumOption = CML.DatumOption.new_datum(plutusData);\n baseBuilder = addressBuilder.with_data(datumOption);\n break;\n }\n default:\n throw new Error(`Unknown outputDatum: ${outputDatum}`);\n }\n } else {\n baseBuilder = addressBuilder;\n }\n\n return scriptRef\n ? baseBuilder.with_reference_script(toScriptRef(scriptRef)).next()\n : baseBuilder.next();\n};\n","import { Effect, pipe } from \"effect\";\nimport { fromHex } from \"@lucid-evolution/core-utils\";\nimport { Assets, Redeemer } from \"@lucid-evolution/core-types\";\nimport * as CML from \"@anastasia-labs/cardano-multiplatform-lib-nodejs\";\nimport { toPartial, toV1, toV2, toV3 } from \"./TxUtils.js\";\nimport { ERROR_MESSAGE, TxBuilderError } from \"../../Errors.js\";\nimport * as TxBuilder from \"../TxBuilder.js\";\nimport { addAssets } from \"@lucid-evolution/utils\";\nimport { TxConfig } from \"./Service.js\";\n\nexport const mintError = (cause: unknown) =>\n new TxBuilderError({ cause: `{ Mint: ${cause} }` });\n\n/**\n * All assets should be of the same policy id.\n * You can chain mintAssets functions together if you need to mint assets with different policy ids.\n * If the plutus script doesn't need a redeemer, you still need to specifiy the void redeemer.\n */\nexport const mintAssets = (assets: Assets) => (redeemer?: Redeemer) =>\n Effect.gen(function* () {\n const { config } = yield* TxConfig;\n const units = Object.keys(assets);\n const policyId = units[0].slice(0, 56);\n const mintAssets = CML.MapAssetNameToNonZeroInt64.new();\n for (const unit of units) {\n if (unit.slice(0, 56) !== policyId) {\n yield* mintError(ERROR_MESSAGE.MULTIPLE_POLICIES);\n }\n mintAssets.insert(CML.AssetName.from_hex(unit.slice(56)), assets[unit]);\n }\n const mintBuilder = CML.SingleMintBuilder.new(mintAssets);\n const policy = yield* pipe(\n Effect.fromNullable(config.scripts.get(policyId)),\n Effect.orElseFail(() =>\n mintError(ERROR_MESSAGE.MISSING_POLICY(policyId)),\n ),\n );\n switch (policy.type) {\n case \"Native\":\n config.txBuilder.add_mint(\n mintBuilder.native_script(\n CML.NativeScript.from_cbor_hex(policy.script),\n CML.NativeScriptWitnessInfo.assume_signature_count(),\n ),\n );\n break;\n\n case \"PlutusV1\": {\n const red = yield* pipe(\n Effect.fromNullable(redeemer),\n Effect.orElseFail(() => mintError(ERROR_MESSAGE.MISSING_REDEEMER)),\n );\n config.txBuilder.add_mint(\n mintBuilder.plutus_script(\n toPartial(toV1(policy.script), red),\n CML.Ed25519KeyHashList.new(),\n ),\n );\n break;\n }\n case \"PlutusV2\": {\n const red = yield* pipe(\n Effect.fromNullable(redeemer),\n Effect.orElseFail(() => mintError(ERROR_MESSAGE.MISSING_REDEEMER)),\n );\n config.txBuilder.add_mint(\n mintBuilder.plutus_script(\n toPartial(toV2(policy.script), red),\n CML.Ed25519KeyHashList.new(),\n ),\n );\n break;\n }\n case \"PlutusV3\": {\n const red = yield* pipe(\n Effect.fromNullable(redeemer),\n Effect.orElseFail(() => mintError(ERROR_MESSAGE.MISSING_REDEEMER)),\n );\n config.txBuilder.add_mint(\n mintBuilder.plutus_script(\n toPartial(toV3(policy.script), red),\n CML.Ed25519KeyHashList.new(),\n ),\n );\n break;\n }\n }\n });\n","import { Effect } from \"effect\";\nimport { UnixTime } from \"@lucid-evolution/core-types\";\nimport * as TxBuilder from \"../TxBuilder.js\";\nimport { unixTimeToSlot } from \"@lucid-evolution/utils\";\nimport { TxConfig } from \"./Service.js\";\n\nexport const validFrom = (unixTime: UnixTime) =>\n Effect.gen(function* () {\n const { config } = yield* TxConfig;\n const slot = unixTimeToSlot(config.lucidConfig.network, unixTime);\n config.txBuilder.set_validity_start_interval(BigInt(slot));\n });\nexport const validTo = (unixTime: UnixTime) =>\n Effect.gen(function* () {\n const { config } = yield* TxConfig;\n const slot = unixTimeToSlot(config.lucidConfig.network, unixTime);\n config.txBuilder.set_ttl(BigInt(slot));\n });\n","import {\n Address,\n PaymentKeyHash,\n RewardAddress,\n StakeKeyHash,\n} from \"@lucid-evolution/core-types\";\nimport * as TxBuilder from \"../TxBuilder.js\";\nimport { Effect, pipe } from \"effect\";\nimport * as CML from \"@anastasia-labs/cardano-multiplatform-lib-nodejs\";\nimport { ERROR_MESSAGE, TxBuilderError } from \"../../Errors.js\";\nimport { validateAddressDetails } from \"./TxUtils.js\";\nimport { TxConfig } from \"./Service.js\";\n\nexport const addSignerError = (cause: unknown) =>\n new TxBuilderError({ cause: `{ Signer: ${cause} }` });\n\nexport const addSigner = (address: Address | RewardAddress) =>\n Effect.gen(function* () {\n const { config } = yield* TxConfig;\n const addressDetails = yield* validateAddressDetails(\n address,\n config.lucidConfig,\n );\n\n const credential =\n addressDetails.type === \"Reward\"\n ? yield* pipe(\n Effect.fromNullable(addressDetails.stakeCredential),\n Effect.orElseFail(() =>\n addSignerError(ERROR_MESSAGE.MISSING_STAKE_CREDENTIAL),\n ),\n )\n : yield* pipe(\n Effect.fromNullable(addressDetails.paymentCredential),\n Effect.orElseFail(() =>\n addSignerError(ERROR_MESSAGE.MISSING_PAYMENT_CREDENTIAL),\n ),\n );\n\n if (credential.type === \"Script\")\n yield* addSignerError(ERROR_MESSAGE.SCRIPT_CREDENTIAL_NOT_ALLOWED);\n\n return credential.hash;\n }).pipe(Effect.flatMap((keyHash) => addSignerKey(keyHash)));\n\n/** Add a payment or stake key hash as a required signer of the transaction. */\nexport const addSignerKey = (keyHash: PaymentKeyHash | StakeKeyHash) =>\n Effect.gen(function* () {\n const { config } = yield* TxConfig;\n config.txBuilder.add_required_signer(CML.Ed25519KeyHash.from_hex(keyHash));\n });\n","import { Lovelace, Redeemer, RewardAddress } from \"@lucid-evolution/core-types\";\nimport * as TxBuilder from \"../TxBuilder.js\";\nimport { Effect, pipe } from \"effect\";\nimport { ERROR_MESSAGE, TxBuilderError } from \"../../Errors.js\";\nimport * as CML from \"@anastasia-labs/cardano-multiplatform-lib-nodejs\";\nimport {\n toPartial,\n toV1,\n toV2,\n toV3,\n validateAddressDetails,\n} from \"./TxUtils.js\";\nimport { TxConfig } from \"./Service.js\";\n\nexport const stakeError = (cause: unknown) =>\n new TxBuilderError({ cause: `{ Stake: ${cause} }` });\n\nexport const registerStake = (rewardAddress: RewardAddress) =>\n Effect.gen(function* () {\n const { config } = yield* TxConfig;\n const addressDetails = yield* pipe(\n validateAddressDetails(rewardAddress, config.lucidConfig),\n Effect.andThen((address) =>\n address.type !== \"Reward\"\n ? stakeError(ERROR_MESSAGE.MISSING_REWARD_TYPE)\n : Effect.succeed(address),\n ),\n );\n\n const stakeCredential = yield* pipe(\n Effect.fromNullable(addressDetails.stakeCredential),\n Effect.orElseFail(() =>\n stakeError(ERROR_MESSAGE.MISSING_STAKE_CREDENTIAL),\n ),\n );\n\n const credential =\n stakeCredential.type === \"Key\"\n ? CML.Credential.new_pub_key(\n CML.Ed25519KeyHash.from_hex(stakeCredential.hash),\n )\n : CML.Credential.new_script(\n CML.ScriptHash.from_hex(stakeCredential.hash),\n );\n const certBuilder = CML.SingleCertificateBuilder.new(\n CML.Certificate.new_stake_registration(credential),\n );\n config.txBuilder.add_cert(certBuilder.skip_witness());\n });\n\nexport const deRegisterStake = (\n rewardAddress: RewardAddress,\n redeemer?: Redeemer,\n) =>\n Effect.gen(function* () {\n const { config } = yield* TxConfig;\n const addressDetails = yield* pipe(\n validateAddressDetails(rewardAddress, config.lucidConfig),\n Effect.andThen((address) =>\n address.type !== \"Reward\"\n ? stakeError(ERROR_MESSAGE.MISSING_REWARD_TYPE)\n : Effect.succeed(address),\n ),\n );\n\n const stakeCredential = yield* pipe(\n Effect.fromNullable(addressDetails.stakeCredential),\n Effect.orElseFail(() =>\n stakeError(ERROR_MESSAGE.MISSING_STAKE_CREDENTIAL),\n ),\n );\n\n const createCertBuilder = (\n credential: CML.Credential,\n config: TxBuilder.TxBuilderConfig,\n ): CML.SingleCertificateBuilder => {\n return CML.SingleCertificateBuilder.new(\n CML.Certificate.new_unreg_cert(\n credential,\n config.lucidConfig.protocolParameters.keyDeposit,\n ),\n );\n };\n\n switch (stakeCredential.type) {\n case \"Key\": {\n const credential = CML.Credential.new_pub_key(\n CML.Ed25519KeyHash.from_hex(stakeCredential.hash),\n );\n const certBuilder = createCertBuilder(credential, config);\n config.txBuilder.add_cert(certBuilder.payment_key());\n break;\n }\n\n case \"Script\": {\n const credential = CML.Credential.new_script(\n CML.ScriptHash.from_hex(stakeCredential.hash),\n );\n const certBuilder = createCertBuilder(credential, config);\n const script = yield* pipe(\n Effect.fromNullable(config.scripts.get(stakeCredential.hash)),\n Effect.orElseFail(() =>\n stakeError(ERROR_MESSAGE.MISSING_SCRIPT(stakeCredential.hash)),\n ),\n );\n const handleRedeemer = () =>\n pipe(\n Effect.fromNullable(redeemer),\n Effect.orElseFail(() => stakeError(ERROR_MESSAGE.MISSING_REDEEMER)),\n );\n switch (script.type) {\n case \"PlutusV1\": {\n const red = yield* handleRedeemer();\n config.txBuilder.add_cert(\n certBuilder.plutus_script(\n toPartial(toV1(script.script), red),\n CML.Ed25519KeyHashList.new(),\n ),\n );\n break;\n }\n\n case \"PlutusV2\": {\n const red = yield* handleRedeemer();\n config.txBuilder.add_cert(\n certBuilder.plutus_script(\n toPartial(toV2(script.script), red),\n CML.Ed25519KeyHashList.new(),\n ),\n );\n break;\n }\n case \"PlutusV3\": {\n const red = yield* handleRedeemer();\n config.txBuilder.add_cert(\n certBuilder.plutus_script(\n toPartial(toV3(script.script), red),\n CML.Ed25519KeyHashList.new(),\n ),\n );\n break;\n }\n case \"Native\": {\n config.txBuilder.add_cert(\n certBuilder.native_script(\n CML.NativeScript.from_cbor_hex(script.script),\n CML.NativeScriptWitnessInfo.assume_signature_count(),\n ),\n );\n break;\n }\n }\n }\n }\n });\n\nexport const withdraw =\n (rewardAddress: RewardAddress, amount: Lovelace) => (redeemer?: Redeemer) =>\n Effect