Skip to content

Commit 936351e

Browse files
feat: tx-builder now supports spending from plutus scripts
BREAKING CHANGE: Input selectors now return selected inputs in lexicographic order - new input selection parameter added 'mustSpendUtxo', which force such UTXOs to be part of the selection - txBuilder now takes a new optional dependency TxEvaluator - added to the txBuilder the following new methods 'addInput', 'addReferenceInput' and 'addDatum' - the txBuilder now supports spending from script inputs - the txBuilder now resolve unknown inputs from on-chain data - outputBuilder 'datum' function can now take PlutusData as inline datum - added to the OutputBuilder a new method 'scriptReference' - walletUtilContext now requires an additional property 'chainHistoryProvider' - initializeTx now takes the list of redeemerByType and the script versions of the plutus scripts in the transaction
1 parent 8b0731d commit 936351e

File tree

45 files changed

+2270
-188
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2270
-188
lines changed

packages/core/src/Serialization/Common/Datum.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const DATUM_ARRAY_SIZE = 2;
1111
*
1212
* @param datum The datum to be checked for.
1313
*/
14-
const isDatumHash = (datum: unknown): datum is Cardano.DatumHash => datum !== null && typeof datum === 'string';
14+
export const isDatumHash = (datum: unknown): datum is Cardano.DatumHash => datum !== null && typeof datum === 'string';
1515

1616
/** Represents different ways of associating a Datum with a UTxO in a transaction. */
1717
export enum DatumKind {

packages/core/src/Serialization/PlutusData/PlutusData.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as Cardano from '../../Cardano';
2+
import * as Crypto from '@cardano-sdk/crypto';
23
import { CborReader, CborReaderState, CborTag, CborWriter } from '../CBOR';
34
import { ConstrPlutusData } from './ConstrPlutusData';
45
import { HexBlob } from '@cardano-sdk/util';
@@ -11,6 +12,7 @@ import { bytesToHex } from '../../util/misc';
1112
const MAX_WORD64 = 18_446_744_073_709_551_615n;
1213
const INDEFINITE_BYTE_STRING = new Uint8Array([95]);
1314
const MAX_BYTE_STRING_CHUNK_SIZE = 64;
15+
const HASH_LENGTH_IN_BYTES = 32;
1416

1517
/**
1618
* A type corresponding to the Plutus Core Data datatype.
@@ -212,6 +214,17 @@ export class PlutusData {
212214
}
213215
}
214216

217+
/**
218+
* Computes the plutus data hash.
219+
*
220+
* @returns the plutus data hash.
221+
*/
222+
hash(): Crypto.Hash32ByteBase16 {
223+
const hash = Crypto.blake2b(HASH_LENGTH_IN_BYTES).update(Buffer.from(this.toCbor(), 'hex')).digest();
224+
225+
return Crypto.Hash32ByteBase16(HexBlob.fromBytes(hash));
226+
}
227+
215228
/**
216229
* Creates a PlutusData object from the given Core PlutusData object.
217230
*

packages/core/src/Serialization/TransactionWitnessSet/Redeemer/Redeemer.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as Cardano from '../../../Cardano';
2+
import * as Crypto from '@cardano-sdk/crypto';
23
import { CborReader, CborWriter } from '../../CBOR';
34
import { ExUnits } from '../../Common';
45
import { HexBlob, InvalidArgumentError, InvalidStateError } from '@cardano-sdk/util';
@@ -7,6 +8,7 @@ import { RedeemerTag } from './RedeemerTag';
78
import { hexToBytes } from '../../../util/misc';
89

910
const REDEEMER_ARRAY_SIZE = 4;
11+
const HASH_LENGTH_IN_BYTES = 32;
1012

1113
/**
1214
* The Redeemer is an argument provided to a Plutus smart contract (script) when
@@ -243,4 +245,15 @@ export class Redeemer {
243245
this.#exUnits = exUnits;
244246
this.#originalBytes = undefined;
245247
}
248+
249+
/**
250+
* Computes the redeemer hash.
251+
*
252+
* @returns the redeemer hash.
253+
*/
254+
hash(): Crypto.Hash32ByteBase16 {
255+
const hash = Crypto.blake2b(HASH_LENGTH_IN_BYTES).update(Buffer.from(this.toCbor(), 'hex')).digest();
256+
257+
return Crypto.Hash32ByteBase16(HexBlob.fromBytes(hash));
258+
}
246259
}

packages/core/test/Serialization/PlutusData.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ describe('PlutusData', () => {
1919
expect(() => Serialization.PlutusData.fromCbor(cbor)).not.toThrowError();
2020
});
2121

22+
it('can compute correct hash', () => {
23+
const data = Serialization.PlutusData.fromCbor(HexBlob('46010203040506'));
24+
25+
// Hash was generated with the CSL
26+
expect(data.hash()).toEqual('f5e45fd57d6c5591dd9e83e76943827c4f4a9eacefd5ac974f48afd8420765a6');
27+
});
28+
2229
describe('Integer', () => {
2330
it('can encode a positive integer', () => {
2431
const data = Serialization.PlutusData.newInteger(5n);

packages/core/test/Serialization/TransactionWitnessSet/Redeemer.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ describe('Redeemer', () => {
4545
expect(redeemer.index()).toEqual(0n);
4646
});
4747

48+
it('can compute correct hash', () => {
49+
const redeemer = Redeemer.fromCore(core);
50+
51+
// Hash was generated with the CSL
52+
expect(redeemer.hash()).toEqual('cfa253874f5f17b01d44e33377124e12fa0e7c8bcd88067fb9edb8c5f5ec662e');
53+
});
54+
4855
describe('Redeemer tag: Spend', () => {
4956
const spendCore = { ...core, purpose: RedeemerPurpose.spend };
5057
const spendCbor = HexBlob('840000d8799f0102030405ff821b000086788ffc4e831b00015060e9e46451');

packages/e2e/test/long-running/multisig-wallet/MultiSigWallet.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ import {
1818
nativeScriptPolicyId,
1919
util
2020
} from '@cardano-sdk/core';
21+
import { GreedyTxEvaluator, defaultSelectionConstraints } from '@cardano-sdk/tx-construction';
2122
import { InputSelector, StaticChangeAddressResolver, roundRobinRandomImprove } from '@cardano-sdk/input-selection';
2223
import { MultiSigTx } from './MultiSigTx';
2324
import { Observable, firstValueFrom, interval, map, switchMap } from 'rxjs';
2425
import { WalletNetworkInfoProvider } from '@cardano-sdk/wallet';
25-
import { defaultSelectionConstraints } from '@cardano-sdk/tx-construction';
2626

2727
const randomHexChar = () => Math.floor(Math.random() * 16).toString(16);
2828
const randomPublicKey = () => Crypto.Ed25519PublicKeyHex(Array.from({ length: 64 }).map(randomHexChar).join(''));
@@ -464,7 +464,9 @@ export class MultiSigWallet {
464464
}
465465
};
466466
},
467-
protocolParameters
467+
protocolParameters,
468+
redeemersByType: {},
469+
txEvaluator: new GreedyTxEvaluator(() => this.#networkInfoProvider.protocolParameters())
468470
});
469471

470472
const implicitCoin = Cardano.util.computeImplicitCoin(protocolParameters, {
@@ -476,6 +478,7 @@ export class MultiSigWallet {
476478
constraints,
477479
implicitValue: { coin: implicitCoin },
478480
outputs: txOuts || new Set(),
481+
preSelectedUtxo: new Set(),
479482
utxo: new Set(utxo)
480483
});
481484

packages/e2e/test/wallet_epoch_0/PersonalWallet/phase2validation.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const localNetworkPlutusV2CostModel = [
1818
64_832, 32, 65_493, 32, 22_558, 32, 16_563, 32, 76_511, 32, 196_500, 453_240, 220, 0, 1, 1, 69_522, 11_687, 0, 1,
1919
60_091, 32, 196_500, 453_240, 220, 0, 1, 1, 196_500, 453_240, 220, 0, 1, 1, 1_159_724, 392_670, 0, 2, 806_990, 30_482,
2020
4, 1_927_926, 82_523, 4, 265_318, 0, 4, 0, 85_931, 32, 205_665, 812, 1, 1, 41_182, 32, 212_342, 32, 31_220, 32,
21-
32_696, 32, 43_357, 32, 32_247, 32, 38_314, 32, 35_892_428, 10, 9_462_713, 1021, 10, 38_887_044, 32_947, 10
21+
32_696, 32, 43_357, 32, 32_247, 32, 38_314, 32, 35_892_428, 10, 57_996_947, 18_975, 10, 38_887_044, 32_947, 10
2222
];
2323

2424
/**
@@ -134,6 +134,7 @@ describe('PersonalWallet/phase2validation', () => {
134134
}
135135
}
136136
]),
137+
redeemersByType: { [Cardano.RedeemerPurpose.mint]: [scriptRedeemer] },
137138
scriptIntegrityHash: scriptDataHash,
138139
witness: { redeemers: [scriptRedeemer], scripts: [alwaysFailScript] }
139140
};

0 commit comments

Comments
 (0)