Skip to content

Commit

Permalink
fixup! feat: tx-builder now supports spending from plutus scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
AngelCastilloB committed May 27, 2024
1 parent 9f93605 commit 2e8f08b
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 46 deletions.
19 changes: 18 additions & 1 deletion packages/tx-construction/src/createTransactionInternals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import * as Crypto from '@cardano-sdk/crypto';
import { Cardano, Serialization, util } from '@cardano-sdk/core';
import { SelectionResult } from '@cardano-sdk/input-selection';
import { TxBodyPreInputSelection } from './types';
import { computeScriptDataHash } from './computeScriptDataHash';
import { getDefaultCostModelsForVersions } from './tx-builder/costModels';

export type CreateTxInternalsProps = {
inputSelection: SelectionResult['selection'];
Expand Down Expand Up @@ -53,16 +55,31 @@ export const createPreInputSelectionTxBody = ({
/** Updates the txBody after input selection takes place with the calculated change and selected inputs */
export const includeChangeAndInputs = ({
bodyPreInputSelection,
inputSelection
inputSelection,
scriptVersions,
witness
}: Pick<CreateTxInternalsProps, 'inputSelection'> & {
bodyPreInputSelection: TxBodyPreInputSelection;
witness?: Cardano.Witness;
scriptVersions?: Set<Cardano.PlutusLanguageVersion>;
}): Cardano.TxBodyWithHash => {
const body: Cardano.TxBody = {
...bodyPreInputSelection,
fee: inputSelection.fee,
inputs: [...inputSelection.inputs].map(([txIn]) => txIn),
outputs: [...inputSelection.outputs, ...inputSelection.change]
};

if (scriptVersions && witness) {
const costModels = getDefaultCostModelsForVersions([...scriptVersions]);
body.scriptIntegrityHash = computeScriptDataHash(
costModels,
[...scriptVersions],
witness.redeemers,
witness.datums
);
}

const serializableBody = Serialization.TransactionBody.fromCore(body);

return {
Expand Down
52 changes: 9 additions & 43 deletions packages/tx-construction/src/tx-builder/TxBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
HandleResolution,
Serialization,
coalesceValueQuantities,
util as coreUtils,
metadatum
} from '@cardano-sdk/core';
import {
Expand Down Expand Up @@ -47,10 +46,8 @@ import { OutputBuilderValidator, TxOutputBuilder } from './OutputBuilder';
import { RedeemersByType, computeMinimumCoinQuantity, tokenBundleSizeExceedsLimit } from '../input-selection';
import { RewardAccountWithPoolId } from '../types';
import { coldObservableProvider } from '@cardano-sdk/util-rxjs';
import { computeScriptDataHash } from '../computeScriptDataHash';
import { contextLogger, deepEquals } from '@cardano-sdk/util';
import { createOutputValidator } from '../output-validation';
import { getDefaultCostModelsForVersions } from './costModels';
import { initializeTx } from './initializeTx';
import { lastValueFrom } from 'rxjs';
import minBy from 'lodash/minBy';
Expand Down Expand Up @@ -424,6 +421,13 @@ export class GenericTxBuilder implements TxBuilder {
? await this.#computeCollateral()
: { collateralReturn: undefined, collaterals: undefined };

const scriptVersions = new Set<Cardano.PlutusLanguageVersion>();
for (const script of this.#knownScripts.values()) {
if (Cardano.isPlutusScript(script)) {
scriptVersions.add(script.version);
}
}

const { body, hash, inputSelection, redeemers } = await initializeTx(
{
auxiliaryData,
Expand All @@ -441,6 +445,7 @@ export class GenericTxBuilder implements TxBuilder {
redeemersByType: this.#knownRedeemers,
referenceInputs: new Set([...this.#referenceInputs.values()].map((utxo) => utxo[0])),
scriptIntegrityHash: hasPlutusScripts ? DUMMY_SCRIPT_DATA_HASH : undefined,
scriptVersions,
signingOptions: partialSigningOptions,
txEvaluator: this.#txEvaluator,
witness
Expand All @@ -449,7 +454,6 @@ export class GenericTxBuilder implements TxBuilder {
);

witness.redeemers = redeemers;
const updateHash = this.#updateHashes(body, witness);

return {
ctx: {
Expand All @@ -464,7 +468,7 @@ export class GenericTxBuilder implements TxBuilder {
witness
},
inputSelection,
tx: { body, hash: updateHash ?? hash }
tx: { body, hash }
};
} catch (error) {
this.#logger.debug('Transaction build error', error);
Expand Down Expand Up @@ -535,44 +539,6 @@ export class GenericTxBuilder implements TxBuilder {
throw new Error('No suitable collateral found');
}

#updateHashes(body: Cardano.TxBody, witness: Cardano.Witness): Cardano.TransactionId | undefined {
const hasPlutusScripts = witness.redeemers ? witness.redeemers.length > 0 : false;

if (hasPlutusScripts) {
const scriptVersions = new Set<Cardano.PlutusLanguageVersion>();

for (const script of this.#knownScripts.values()) {
if (Cardano.isPlutusScript(script)) {
scriptVersions.add(script.version);
}
}

const datumsToHash = [];

for (const [key, value] of this.#knownDatums) {
if (!this.#knownInlineDatums.has(key)) datumsToHash.push(value);
}

const costModels = getDefaultCostModelsForVersions([...scriptVersions]);
body.scriptIntegrityHash = computeScriptDataHash(
costModels,
[...scriptVersions],
witness.redeemers,
datumsToHash
);

const serializableBody = Serialization.TransactionBody.fromCore(body);

return Cardano.TransactionId.fromHexBlob(
coreUtils.bytesToHex(
Crypto.blake2b(Crypto.blake2b.BYTES).update(coreUtils.hexToBytes(serializableBody.toCbor())).digest()
)
);
}

return undefined;
}

async #buildWitness(): Promise<Cardano.Witness> {
const witnesses = { signatures: new Map() } as Cardano.Witness;

Expand Down
11 changes: 9 additions & 2 deletions packages/tx-construction/src/tx-builder/initializeTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ export const initializeTx = async (
}
const unwitnessedTx = includeChangeAndInputs({
bodyPreInputSelection,
inputSelection
inputSelection,
scriptVersions: props.scriptVersions,
witness: props.witness as Cardano.Witness
});

const dRepPublicKey = addressManager
Expand Down Expand Up @@ -111,9 +113,14 @@ export const initializeTx = async (
utxo: new Set(utxo)
});

const witness = { ...props.witness, redeemers } as Cardano.Witness;

const { body, hash } = includeChangeAndInputs({
bodyPreInputSelection,
inputSelection
inputSelection,
scriptVersions: props.scriptVersions,
witness
});

return { body, hash, inputSelection, redeemers };
};
1 change: 1 addition & 0 deletions packages/tx-construction/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export interface InitializeTxProps {
customizeCb?: CustomizeCb;
txEvaluator: TxEvaluator;
redeemersByType?: RedeemersByType;
scriptVersions?: Set<Cardano.PlutusLanguageVersion>;
}

export interface InitializeTxPropsValidationResult {
Expand Down

0 comments on commit 2e8f08b

Please sign in to comment.