@meshsdk/transaction 1.6.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1180 @@
1
+ import {
2
+ Asset,
3
+ Data,
4
+ LanguageVersion,
5
+ PoolParams,
6
+ UTxO,
7
+ DEFAULT_REDEEMER_BUDGET,
8
+ MintItem,
9
+ TxIn,
10
+ PubKeyTxIn,
11
+ MeshTxBuilderBody,
12
+ RefTxIn,
13
+ Output,
14
+ BuilderData,
15
+ TxInParameter,
16
+ Quantity,
17
+ Unit,
18
+ RequiredWith,
19
+ Action,
20
+ Protocol,
21
+ DEFAULT_PROTOCOL_PARAMETERS,
22
+ Withdrawal,
23
+ Redeemer,
24
+ emptyTxBuilderBody,
25
+ } from "@meshsdk/common";
26
+ import JSONBig from "json-bigint";
27
+ import { experimentalSelectUtxos } from "../utxo-selection";
28
+
29
+ export class MeshTxBuilderCore {
30
+ txEvaluationMultiplier = 1.1;
31
+ private txOutput?: Output;
32
+ private addingPlutusScriptInput = false;
33
+ private plutusSpendingScriptVersion: LanguageVersion | undefined;
34
+ private addingPlutusMint = false;
35
+ private plutusMintingScriptVersion: LanguageVersion | undefined;
36
+ private addingPlutusWithdrawal = false;
37
+ private plutusWithdrawalScriptVersion: LanguageVersion | undefined;
38
+
39
+ protected _protocolParams: Protocol = DEFAULT_PROTOCOL_PARAMETERS;
40
+
41
+ protected mintItem?: MintItem;
42
+
43
+ protected txInQueueItem?: TxIn;
44
+
45
+ protected withdrawalItem?: Withdrawal;
46
+
47
+ protected collateralQueueItem?: PubKeyTxIn;
48
+
49
+ protected refScriptTxInQueueItem?: RefTxIn;
50
+
51
+ meshTxBuilderBody: MeshTxBuilderBody;
52
+
53
+ constructor() {
54
+ this.meshTxBuilderBody = emptyTxBuilderBody();
55
+ }
56
+
57
+ /**
58
+ * Set the input for transaction
59
+ * @param txHash The transaction hash of the input UTxO
60
+ * @param txIndex The transaction index of the input UTxO
61
+ * @param amount The asset amount of index of the input UTxO
62
+ * @param address The address of the input UTxO
63
+ * @returns The MeshTxBuilder instance
64
+ */
65
+ txIn = (
66
+ txHash: string,
67
+ txIndex: number,
68
+ amount?: Asset[],
69
+ address?: string
70
+ ) => {
71
+ if (this.txInQueueItem) {
72
+ this.queueInput();
73
+ }
74
+ if (!this.addingPlutusScriptInput) {
75
+ this.txInQueueItem = {
76
+ type: "PubKey",
77
+ txIn: {
78
+ txHash: txHash,
79
+ txIndex: txIndex,
80
+ amount: amount,
81
+ address: address,
82
+ },
83
+ };
84
+ } else {
85
+ this.txInQueueItem = {
86
+ type: "Script",
87
+ txIn: {
88
+ txHash: txHash,
89
+ txIndex: txIndex,
90
+ amount: amount,
91
+ address: address,
92
+ },
93
+ scriptTxIn: {},
94
+ };
95
+ }
96
+ this.addingPlutusScriptInput = false;
97
+ return this;
98
+ };
99
+
100
+ /**
101
+ * Set the script for transaction input
102
+ * @param {string} scriptCbor The CborHex of the script
103
+ * @param version Optional - The Plutus script version
104
+ * @returns The MeshTxBuilder instance
105
+ */
106
+ txInScript = (scriptCbor: string) => {
107
+ if (!this.txInQueueItem) throw Error("Undefined input");
108
+ if (this.txInQueueItem.type === "PubKey") {
109
+ this.txInQueueItem = {
110
+ type: "SimpleScript",
111
+ txIn: this.txInQueueItem.txIn,
112
+ simpleScriptTxIn: {
113
+ scriptSource: {
114
+ type: "Provided",
115
+ script: scriptCbor,
116
+ },
117
+ },
118
+ };
119
+ }
120
+ if (this.txInQueueItem.type === "Script") {
121
+ this.txInQueueItem.scriptTxIn.scriptSource = {
122
+ type: "Provided",
123
+ script: {
124
+ code: scriptCbor,
125
+ version: this.plutusSpendingScriptVersion || "V2",
126
+ },
127
+ };
128
+ }
129
+ return this;
130
+ };
131
+
132
+ /**
133
+ * Set the input datum for transaction input
134
+ * @param datum The datum in Mesh Data type, JSON in raw constructor like format, or CBOR hex string
135
+ * @param type The datum type, either Mesh Data type, JSON in raw constructor like format, or CBOR hex string
136
+ * @returns The MeshTxBuilder instance
137
+ */
138
+ txInDatumValue = (
139
+ datum: BuilderData["content"],
140
+ type: BuilderData["type"] = "Mesh"
141
+ ) => {
142
+ if (!this.txInQueueItem) throw Error("Undefined input");
143
+ if (this.txInQueueItem.type === "PubKey")
144
+ throw Error("Datum value attempted to be called a non script input");
145
+ if (this.txInQueueItem.type === "SimpleScript")
146
+ throw Error(
147
+ "Datum value attempted to be called on a simple script input"
148
+ );
149
+
150
+ let content = datum;
151
+ if (type === "JSON") {
152
+ content = this.castRawDataToJsonString(datum as object | string);
153
+ }
154
+ if (type === "Mesh") {
155
+ this.txInQueueItem.scriptTxIn.datumSource = {
156
+ type: "Provided",
157
+ data: {
158
+ type,
159
+ content: datum as Data,
160
+ },
161
+ };
162
+ return this;
163
+ }
164
+ this.txInQueueItem.scriptTxIn.datumSource = {
165
+ type: "Provided",
166
+ data: {
167
+ type,
168
+ content: content as string,
169
+ },
170
+ };
171
+ return this;
172
+ };
173
+
174
+ /**
175
+ * Tell the transaction builder that the input UTxO has inlined datum
176
+ * @returns The MeshTxBuilder instance
177
+ */
178
+ txInInlineDatumPresent = () => {
179
+ if (!this.txInQueueItem) throw Error("Undefined input");
180
+ if (this.txInQueueItem.type === "PubKey")
181
+ throw Error(
182
+ "Inline datum present attempted to be called a non script input"
183
+ );
184
+ if (this.txInQueueItem.type === "SimpleScript")
185
+ throw Error(
186
+ "Inline datum present attempted to be called on a simple script input"
187
+ );
188
+ const { txHash, txIndex } = this.txInQueueItem.txIn;
189
+ if (txHash && txIndex.toString()) {
190
+ this.txInQueueItem.scriptTxIn.datumSource = {
191
+ type: "Inline",
192
+ txHash,
193
+ txIndex,
194
+ };
195
+ }
196
+ return this;
197
+ };
198
+
199
+ // /**
200
+ // * Native script - Set the reference input where it would also be spent in the transaction
201
+ // * @param txHash The transaction hash of the reference UTxO
202
+ // * @param txIndex The transaction index of the reference UTxO
203
+ // * @param spendingScriptHash The script hash of the spending script
204
+ // * @returns The MeshTxBuilder instance
205
+ // */
206
+ // simpleScriptTxInReference = (
207
+ // txHash: string,
208
+ // txIndex: number,
209
+ // spendingScriptHash?: string
210
+ // ) => {
211
+ // if (!this.txInQueueItem) throw Error('Undefined input');
212
+ // if (this.txInQueueItem.type === 'PubKey')
213
+ // throw Error(
214
+ // 'Spending tx in reference attempted to be called a non script input'
215
+ // );
216
+ // this.txInQueueItem.scriptTxIn.scriptSource = {
217
+ // type: 'Inline',
218
+ // txInInfo: {
219
+ // txHash,
220
+ // txIndex,
221
+ // spendingScriptHash,
222
+ // },
223
+ // };
224
+ // return this;
225
+ // };
226
+
227
+ /**
228
+ * Set the redeemer for the reference input to be spent in same transaction
229
+ * @param redeemer The redeemer in Mesh Data type, JSON in raw constructor like format, or CBOR hex string
230
+ * @param type The redeemer data type, either Mesh Data type, JSON in raw constructor like format, or CBOR hex string
231
+ * @param exUnits The execution units budget for the redeemer
232
+ * @returns The MeshTxBuilder instance
233
+ */
234
+ txInRedeemerValue = (
235
+ redeemer: BuilderData["content"],
236
+ type: BuilderData["type"] = "Mesh",
237
+ exUnits = { ...DEFAULT_REDEEMER_BUDGET }
238
+ ) => {
239
+ if (!this.txInQueueItem) throw Error("Undefined input");
240
+ if (this.txInQueueItem.type === "PubKey")
241
+ throw Error(
242
+ "Spending tx in reference redeemer attempted to be called a non script input"
243
+ );
244
+ if (this.txInQueueItem.type === "SimpleScript")
245
+ throw Error(
246
+ "Spending tx in reference redeemer attempted to be called on a simple script input"
247
+ );
248
+ this.txInQueueItem.scriptTxIn.redeemer = this.castBuilderDataToRedeemer(
249
+ redeemer,
250
+ type,
251
+ exUnits
252
+ );
253
+ return this;
254
+ };
255
+
256
+ /**
257
+ * Set the output for transaction
258
+ * @param {string} address The recipient of the output
259
+ * @param {Asset[]} amount The amount of other native assets attached with UTxO
260
+ * @returns The MeshTxBuilder instance
261
+ */
262
+ txOut = (address: string, amount: Asset[]) => {
263
+ if (this.txOutput) {
264
+ this.meshTxBuilderBody.outputs.push(this.txOutput);
265
+ this.txOutput = undefined;
266
+ }
267
+ this.txOutput = {
268
+ address,
269
+ amount,
270
+ };
271
+ return this;
272
+ };
273
+
274
+ /**
275
+ * Set the output datum hash for transaction
276
+ * @param datum The datum in Mesh Data type, JSON in raw constructor like format, or CBOR hex string
277
+ * @param type The datum type, either Mesh Data type, JSON in raw constructor like format, or CBOR hex string
278
+ * @returns The MeshTxBuilder instance
279
+ */
280
+ txOutDatumHashValue = (
281
+ datum: BuilderData["content"],
282
+ type: BuilderData["type"] = "Mesh"
283
+ ) => {
284
+ let content = datum;
285
+ if (this.txOutput) {
286
+ if (type === "Mesh") {
287
+ this.txOutput.datum = {
288
+ type: "Hash",
289
+ data: {
290
+ type,
291
+ content: content as Data,
292
+ },
293
+ };
294
+ return this;
295
+ }
296
+ if (type === "JSON") {
297
+ content = this.castRawDataToJsonString(datum as object | string);
298
+ }
299
+ this.txOutput.datum = {
300
+ type: "Hash",
301
+ data: {
302
+ type,
303
+ content: content as string,
304
+ },
305
+ };
306
+ }
307
+ return this;
308
+ };
309
+
310
+ /**
311
+ * Set the output inline datum for transaction
312
+ * @param datum The datum in Mesh Data type, JSON in raw constructor like format, or CBOR hex string
313
+ * @param type The datum type, either Mesh Data type, JSON in raw constructor like format, or CBOR hex string
314
+ * @returns The MeshTxBuilder instance
315
+ */
316
+ txOutInlineDatumValue = (
317
+ datum: BuilderData["content"],
318
+ type: BuilderData["type"] = "Mesh"
319
+ ) => {
320
+ let content = datum;
321
+ if (this.txOutput) {
322
+ if (type === "Mesh") {
323
+ this.txOutput.datum = {
324
+ type: "Inline",
325
+ data: {
326
+ type,
327
+ content: content as Data,
328
+ },
329
+ };
330
+ return this;
331
+ }
332
+ if (type === "JSON") {
333
+ content = this.castRawDataToJsonString(datum as object | string);
334
+ }
335
+ this.txOutput.datum = {
336
+ type: "Inline",
337
+ data: {
338
+ type,
339
+ content: content as string,
340
+ },
341
+ };
342
+ }
343
+ return this;
344
+ };
345
+
346
+ /**
347
+ * Set the reference script to be attached with the output
348
+ * @param scriptCbor The CBOR hex of the script to be attached to UTxO as reference script
349
+ * @param version Optional - The Plutus script version
350
+ * @returns The MeshTxBuilder instance
351
+ */
352
+ txOutReferenceScript = (
353
+ scriptCbor: string,
354
+ version: LanguageVersion = "V2"
355
+ ) => {
356
+ if (this.txOutput) {
357
+ this.txOutput.referenceScript = { code: scriptCbor, version };
358
+ }
359
+ return this;
360
+ };
361
+
362
+ /**
363
+ * Set the instruction that it is currently using V1 Plutus spending scripts
364
+ * @returns The MeshTxBuilder instance
365
+ */
366
+ spendingPlutusScriptV1 = () => {
367
+ // This flag should signal a start to a script input
368
+ // The next step after will be to add a tx-in
369
+ // After which, we will REQUIRE, script, datum and redeemer info
370
+ // for unlocking this particular input
371
+ this.addingPlutusScriptInput = true;
372
+ this.plutusSpendingScriptVersion = "V1";
373
+ return this;
374
+ };
375
+ /**
376
+ * Set the instruction that it is currently using V2 Plutus spending scripts
377
+ * @returns The MeshTxBuilder instance
378
+ */
379
+ spendingPlutusScriptV2 = () => {
380
+ // This flag should signal a start to a script input
381
+ // The next step after will be to add a tx-in
382
+ // After which, we will REQUIRE, script, datum and redeemer info
383
+ // for unlocking this particular input
384
+ this.addingPlutusScriptInput = true;
385
+ this.plutusSpendingScriptVersion = "V2";
386
+ return this;
387
+ };
388
+ /**
389
+ * Set the instruction that it is currently using V3 Plutus spending scripts
390
+ * @returns The MeshTxBuilder instance
391
+ */
392
+ spendingPlutusScriptV3 = () => {
393
+ // This flag should signal a start to a script input
394
+ // The next step after will be to add a tx-in
395
+ // After which, we will REQUIRE, script, datum and redeemer info
396
+ // for unlocking this particular input
397
+ this.addingPlutusScriptInput = true;
398
+ this.plutusSpendingScriptVersion = "V3";
399
+ return this;
400
+ };
401
+
402
+ /**
403
+ * Set the reference input where it would also be spent in the transaction
404
+ * @param txHash The transaction hash of the reference UTxO
405
+ * @param txIndex The transaction index of the reference UTxO
406
+ * @param spendingScriptHash The script hash of the spending script
407
+ * @returns The MeshTxBuilder instance
408
+ */
409
+ spendingTxInReference = (
410
+ txHash: string,
411
+ txIndex: number,
412
+ spendingScriptHash?: string
413
+ ) => {
414
+ if (!this.txInQueueItem) throw Error("Undefined input");
415
+ if (this.txInQueueItem.type === "PubKey")
416
+ throw Error(
417
+ "Spending tx in reference attempted to be called a non script input"
418
+ );
419
+ if (this.txInQueueItem.type === "SimpleScript")
420
+ throw Error(
421
+ "Spending tx in reference attempted to be called on a simple script input"
422
+ );
423
+ this.txInQueueItem.scriptTxIn.scriptSource = {
424
+ type: "Inline",
425
+ txHash,
426
+ txIndex,
427
+ scriptHash: spendingScriptHash,
428
+ version: this.plutusSpendingScriptVersion || "V2",
429
+ scriptSize: "0", // TODO
430
+ };
431
+ return this;
432
+ };
433
+
434
+ /**
435
+ * [Alias of txInInlineDatumPresent] Set the instruction that the reference input has inline datum
436
+ * @returns The MeshTxBuilder instance
437
+ */
438
+ // Unsure how this is different from the --tx-in-inline-datum-present flag
439
+ // It seems to just be different based on if the script is a reference input
440
+ spendingReferenceTxInInlineDatumPresent = () => {
441
+ this.txInInlineDatumPresent();
442
+ return this;
443
+ };
444
+
445
+ /**
446
+ * [Alias of txInRedeemerValue] Set the redeemer for the reference input to be spent in same transaction
447
+ * @param redeemer The redeemer in Mesh Data type, JSON in raw constructor like format, or CBOR hex string
448
+ * @param type The redeemer data type, either Mesh Data type, JSON in raw constructor like format, or CBOR hex string
449
+ * @param exUnits The execution units budget for the redeemer
450
+ * @returns The MeshTxBuilder instance
451
+ */
452
+ spendingReferenceTxInRedeemerValue = (
453
+ redeemer: BuilderData["content"],
454
+ type: BuilderData["type"] = "Mesh",
455
+ exUnits = { ...DEFAULT_REDEEMER_BUDGET }
456
+ ) => {
457
+ this.txInRedeemerValue(redeemer, type, exUnits);
458
+ return this;
459
+ };
460
+
461
+ /**
462
+ * Specify a read only reference input. This reference input is not witnessing anything it is simply provided in the plutus script context.
463
+ * @param txHash The transaction hash of the reference UTxO
464
+ * @param txIndex The transaction index of the reference UTxO
465
+ * @returns The MeshTxBuilder instance
466
+ */
467
+ readOnlyTxInReference = (txHash: string, txIndex: number) => {
468
+ this.meshTxBuilderBody.referenceInputs.push({ txHash, txIndex });
469
+ return this;
470
+ };
471
+
472
+ /**
473
+ * Set the instruction that it is currently using V1 Plutus minting scripts
474
+ * @returns The MeshTxBuilder instance
475
+ */
476
+ mintPlutusScriptV1 = () => {
477
+ this.addingPlutusMint = true;
478
+ this.plutusMintingScriptVersion = "V1";
479
+ return this;
480
+ };
481
+ /**
482
+ * Set the instruction that it is currently using V2 Plutus minting scripts
483
+ * @returns The MeshTxBuilder instance
484
+ */
485
+ mintPlutusScriptV2 = () => {
486
+ this.addingPlutusMint = true;
487
+ this.plutusMintingScriptVersion = "V2";
488
+ return this;
489
+ };
490
+ /**
491
+ * Set the instruction that it is currently using V3 Plutus minting scripts
492
+ * @returns The MeshTxBuilder instance
493
+ */
494
+ mintPlutusScriptV3 = () => {
495
+ this.addingPlutusMint = true;
496
+ this.plutusMintingScriptVersion = "V3";
497
+ return this;
498
+ };
499
+
500
+ /**
501
+ * Set the minting value of transaction
502
+ * @param quantity The quantity of asset to be minted
503
+ * @param policy The policy id of the asset to be minted
504
+ * @param name The hex of token name of the asset to be minted
505
+ * @returns The MeshTxBuilder instance
506
+ */
507
+ mint = (quantity: string, policy: string, name: string) => {
508
+ if (this.mintItem) {
509
+ this.queueMint();
510
+ }
511
+ this.mintItem = {
512
+ type: this.addingPlutusMint ? "Plutus" : "Native",
513
+ policyId: policy,
514
+ assetName: name,
515
+ amount: quantity,
516
+ };
517
+ this.addingPlutusMint = false;
518
+ return this;
519
+ };
520
+
521
+ /**
522
+ * Set the minting script of current mint
523
+ * @param scriptCBOR The CBOR hex of the minting policy script
524
+ * @param version Optional - The Plutus script version
525
+ * @returns The MeshTxBuilder instance
526
+ */
527
+ mintingScript = (scriptCBOR: string) => {
528
+ if (!this.mintItem) throw Error("Undefined mint");
529
+ if (!this.mintItem.type) throw Error("Mint information missing");
530
+ if (this.mintItem.type === "Native") {
531
+ this.mintItem.scriptSource = {
532
+ type: "Provided",
533
+ scriptCode: scriptCBOR,
534
+ };
535
+ }
536
+ if (this.mintItem.type === "Plutus") {
537
+ this.mintItem.scriptSource = {
538
+ type: "Provided",
539
+ script: {
540
+ code: scriptCBOR,
541
+ version: this.plutusMintingScriptVersion || "V2",
542
+ },
543
+ };
544
+ }
545
+
546
+ return this;
547
+ };
548
+
549
+ /**
550
+ * Use reference script for minting
551
+ * @param txHash The transaction hash of the UTxO
552
+ * @param txIndex The transaction index of the UTxO
553
+ * @returns The MeshTxBuilder instance
554
+ */
555
+ mintTxInReference = (txHash: string, txIndex: number) => {
556
+ if (!this.mintItem) throw Error("Undefined mint");
557
+ if (!this.mintItem.type) throw Error("Mint information missing");
558
+ if (this.mintItem.type == "Native") {
559
+ throw Error(
560
+ "Mint tx in reference can only be used on plutus script tokens"
561
+ );
562
+ }
563
+ if (!this.mintItem.policyId)
564
+ throw Error("PolicyId information missing from mint asset");
565
+ this.mintItem.scriptSource = {
566
+ type: "Inline",
567
+ txHash,
568
+ txIndex,
569
+ version: this.plutusMintingScriptVersion,
570
+ scriptSize: "0", // TODO
571
+ scriptHash: "", // TODO
572
+ };
573
+ return this;
574
+ };
575
+
576
+ /**
577
+ * Set the redeemer for minting
578
+ * @param redeemer The redeemer in Mesh Data type, JSON in raw constructor like format, or CBOR hex string
579
+ * @param type The redeemer data type, either Mesh Data type, JSON in raw constructor like format, or CBOR hex string
580
+ * @param exUnits The execution units budget for the redeemer
581
+ * @returns The MeshTxBuilder instance
582
+ */
583
+ mintReferenceTxInRedeemerValue = (
584
+ redeemer: BuilderData["content"],
585
+ type: BuilderData["type"] = "Mesh",
586
+ exUnits = { ...DEFAULT_REDEEMER_BUDGET }
587
+ ) => {
588
+ if (!this.mintItem) throw Error("Undefined mint");
589
+ if (this.mintItem.type == "Native") {
590
+ throw Error(
591
+ "Mint tx in reference can only be used on plutus script tokens"
592
+ );
593
+ } else if (this.mintItem.type == "Plutus") {
594
+ if (!this.mintItem.policyId)
595
+ throw Error("PolicyId information missing from mint asset");
596
+ }
597
+ this.mintItem.redeemer = this.castBuilderDataToRedeemer(
598
+ redeemer,
599
+ type,
600
+ exUnits
601
+ );
602
+ return this;
603
+ };
604
+
605
+ /**
606
+ * Set the redeemer for the reference input to be spent in same transaction
607
+ * @param redeemer The redeemer in Mesh Data type, JSON in raw constructor like format, or CBOR hex string
608
+ * @param type The redeemer data type, either Mesh Data type, JSON in raw constructor like format, or CBOR hex string
609
+ * @param exUnits The execution units budget for the redeemer
610
+ * @returns The MeshTxBuilder instance
611
+ */
612
+ mintRedeemerValue = (
613
+ redeemer: BuilderData["content"],
614
+ type: BuilderData["type"] = "Mesh",
615
+ exUnits = { ...DEFAULT_REDEEMER_BUDGET }
616
+ ) => {
617
+ this.mintReferenceTxInRedeemerValue(redeemer, type, exUnits);
618
+ return this;
619
+ };
620
+
621
+ /**
622
+ * Set the required signer of the transaction
623
+ * @param pubKeyHash The PubKeyHash of the required signer
624
+ * @returns The MeshTxBuilder instance
625
+ */
626
+ requiredSignerHash = (pubKeyHash: string) => {
627
+ this.meshTxBuilderBody.requiredSignatures.push(pubKeyHash);
628
+ return this;
629
+ };
630
+
631
+ /**
632
+ * Set the collateral UTxO for the transaction
633
+ * @param txHash The transaction hash of the collateral UTxO
634
+ * @param txIndex The transaction index of the collateral UTxO
635
+ * @param amount The asset amount of index of the collateral UTxO
636
+ * @param address The address of the collateral UTxO
637
+ * @returns The MeshTxBuilder instance
638
+ */
639
+ txInCollateral = (
640
+ txHash: string,
641
+ txIndex: number,
642
+ amount?: Asset[],
643
+ address?: string
644
+ ) => {
645
+ if (this.collateralQueueItem) {
646
+ this.meshTxBuilderBody.collaterals.push(this.collateralQueueItem);
647
+ }
648
+ this.collateralQueueItem = {
649
+ type: "PubKey",
650
+ txIn: {
651
+ txHash: txHash,
652
+ txIndex: txIndex,
653
+ amount,
654
+ address,
655
+ },
656
+ };
657
+ return this;
658
+ };
659
+
660
+ /**
661
+ * Set the instruction that it is currently using V1 Plutus withdrawal scripts
662
+ * @returns The MeshTxBuilder instance
663
+ */
664
+ withdrawalPlutusScriptV1 = () => {
665
+ this.addingPlutusWithdrawal = true;
666
+ this.plutusWithdrawalScriptVersion = "V1";
667
+ return this;
668
+ };
669
+
670
+ /**
671
+ * Set the instruction that it is currently using V2 Plutus withdrawal scripts
672
+ * @returns The MeshTxBuilder instance
673
+ */
674
+ withdrawalPlutusScriptV2 = () => {
675
+ this.addingPlutusWithdrawal = true;
676
+ this.plutusWithdrawalScriptVersion = "V2";
677
+ return this;
678
+ };
679
+
680
+ /**
681
+ * Set the instruction that it is currently using V3 Plutus withdrawal scripts
682
+ * @returns The MeshTxBuilder instance
683
+ */
684
+ withdrawalPlutusScriptV3 = () => {
685
+ this.addingPlutusWithdrawal = true;
686
+ this.plutusWithdrawalScriptVersion = "V3";
687
+ return this;
688
+ };
689
+
690
+ /**
691
+ * Withdraw stake rewards in the MeshTxBuilder instance
692
+ * @param stakeAddress The address corresponding to the stake key
693
+ * @param coin The amount of lovelaces in the withdrawal
694
+ * @returns The MeshTxBuilder instance
695
+ */
696
+ withdrawal = (stakeAddress: string, coin: string) => {
697
+ if (this.withdrawalItem) {
698
+ this.queueWithdrawal();
699
+ }
700
+ if (this.addingPlutusWithdrawal) {
701
+ const withdrawal: Withdrawal = {
702
+ plutusScriptWithdrawal: {
703
+ address: stakeAddress,
704
+ coin: coin,
705
+ },
706
+ };
707
+ this.meshTxBuilderBody.withdrawals.push(withdrawal);
708
+ return this;
709
+ }
710
+ const withdrawal: Withdrawal = {
711
+ pubKeyWithdrawal: {
712
+ address: stakeAddress,
713
+ coin: coin,
714
+ },
715
+ };
716
+ this.meshTxBuilderBody.withdrawals.push(withdrawal);
717
+ return this;
718
+ };
719
+
720
+ /**
721
+ * Add a withdrawal script to the MeshTxBuilder instance
722
+ * @param scriptCbor The script in CBOR format
723
+ * @param version The language version
724
+ * @returns The MeshTxBuilder instance
725
+ */
726
+ withdrawalScript = (scriptCbor: string, version: LanguageVersion) => {
727
+ if (!this.withdrawalItem)
728
+ throw Error("withdrawalScript: Undefined withdrawal");
729
+ if (!("plutusScriptWithdrawal" in this.withdrawalItem))
730
+ throw Error("withdrawalScript: Adding script to non plutus withdrawal");
731
+ this.withdrawalItem.plutusScriptWithdrawal.scriptSource = {
732
+ type: "Provided",
733
+ script: {
734
+ code: scriptCbor,
735
+ version: this.plutusWithdrawalScriptVersion || "V2",
736
+ },
737
+ };
738
+ return this;
739
+ };
740
+
741
+ /**
742
+ * Add a withdrawal reference to the MeshTxBuilder instance
743
+ * @param txHash The transaction hash of reference UTxO
744
+ * @param txIndex The transaction index of reference UTxO
745
+ * @param withdrawalScriptHash The script hash of the withdrawal script
746
+ * @param scriptSize The script size of the withdrawal script
747
+ * @returns The MeshTxBuilder instance
748
+ */
749
+ withdrawalTxInReference = (
750
+ txHash: string,
751
+ txIndex: number,
752
+ withdrawalScriptHash?: string,
753
+ scriptSize?: string
754
+ ) => {
755
+ if (!this.withdrawalItem)
756
+ throw Error("withdrawalTxInReference: Undefined withdrawal");
757
+ if (!("plutusScriptWithdrawal" in this.withdrawalItem))
758
+ throw Error(
759
+ "withdrawalTxInReference: Adding script reference to non plutus withdrawal"
760
+ );
761
+ this.withdrawalItem.plutusScriptWithdrawal.scriptSource = {
762
+ type: "Inline",
763
+ txHash,
764
+ txIndex,
765
+ scriptHash: withdrawalScriptHash,
766
+ version: this.plutusWithdrawalScriptVersion || "V2",
767
+ scriptSize: scriptSize || "0",
768
+ };
769
+ };
770
+
771
+ /**
772
+ * Set the transaction withdrawal redeemer value in the MeshTxBuilder instance
773
+ * @param redeemer The redeemer in Mesh Data type, JSON in raw constructor like format, or CBOR hex string
774
+ * @param type The redeemer data type, either Mesh Data type, JSON in raw constructor like format, or CBOR hex string
775
+ * @param exUnits The execution units budget for the redeemer
776
+ * @returns The MeshTxBuilder instance
777
+ */
778
+ withdrawalRedeemerValue = (
779
+ redeemer: BuilderData["content"],
780
+ type: BuilderData["type"] = "Mesh",
781
+ exUnits = { ...DEFAULT_REDEEMER_BUDGET }
782
+ ) => {
783
+ if (!this.withdrawalItem)
784
+ throw Error("withdrawalRedeemerValue: Undefined withdrawal");
785
+ if (!("plutusScriptWithdrawal" in this.withdrawalItem))
786
+ throw Error(
787
+ "withdrawalRedeemerValue: Adding redeemer to non plutus withdrawal"
788
+ );
789
+ this.withdrawalItem.plutusScriptWithdrawal.redeemer =
790
+ this.castBuilderDataToRedeemer(redeemer, type, exUnits);
791
+
792
+ return this;
793
+ };
794
+
795
+ /**
796
+ * Creates a pool registration certificate, and adds it to the transaction
797
+ * @param poolParams Parameters for pool registration
798
+ * @returns The MeshTxBuilder instance
799
+ */
800
+ registerPoolCertificate = (poolParams: PoolParams) => {
801
+ this.meshTxBuilderBody.certificates.push({
802
+ type: "RegisterPool",
803
+ poolParams,
804
+ });
805
+ return this;
806
+ };
807
+
808
+ /**
809
+ * Creates a stake registration certificate, and adds it to the transaction
810
+ * @param stakeKeyHash The keyHash of the stake key
811
+ * @returns The MeshTxBuilder instance
812
+ */
813
+ registerStakeCertificate = (stakeKeyHash: string) => {
814
+ this.meshTxBuilderBody.certificates.push({
815
+ type: "RegisterStake",
816
+ stakeKeyHash,
817
+ });
818
+ return this;
819
+ };
820
+
821
+ /**
822
+ * Creates a stake delegation certificate, and adds it to the transaction
823
+ * This will delegate stake from the corresponding stake address to the pool
824
+ * @param stakeKeyHash The keyHash of the stake key
825
+ * @param poolId poolId can be in either bech32 or hex form
826
+ * @returns The MeshTxBuilder instance
827
+ */
828
+ delegateStakeCertificate = (stakeKeyHash: string, poolId: string) => {
829
+ this.meshTxBuilderBody.certificates.push({
830
+ type: "DelegateStake",
831
+ stakeKeyHash,
832
+ poolId,
833
+ });
834
+ return this;
835
+ };
836
+
837
+ /**
838
+ * Creates a stake deregister certificate, and adds it to the transaction
839
+ * @param stakeKeyHash The keyHash of the stake key
840
+ * @returns The MeshTxBuilder instance
841
+ */
842
+ deregisterStakeCertificate = (stakeKeyHash: string) => {
843
+ this.meshTxBuilderBody.certificates.push({
844
+ type: "DeregisterStake",
845
+ stakeKeyHash,
846
+ });
847
+ return this;
848
+ };
849
+
850
+ /**
851
+ * Creates a pool retire certificate, and adds it to the transaction
852
+ * @param poolId poolId can be in either bech32 or hex form
853
+ * @param epoch The intended epoch to retire the pool
854
+ * @returns The MeshTxBuilder instance
855
+ */
856
+ retirePoolCertificate = (poolId: string, epoch: number) => {
857
+ this.meshTxBuilderBody.certificates.push({
858
+ type: "RetirePool",
859
+ poolId,
860
+ epoch,
861
+ });
862
+ return this;
863
+ };
864
+
865
+ /**
866
+ * Configure the address to accept change UTxO
867
+ * @param addr The address to accept change UTxO
868
+ * @returns The MeshTxBuilder instance
869
+ */
870
+ changeAddress = (addr: string) => {
871
+ this.meshTxBuilderBody.changeAddress = addr;
872
+ return this;
873
+ };
874
+
875
+ /**
876
+ * Set the transaction valid interval to be valid only after the slot
877
+ * @param slot The transaction is valid only after this slot
878
+ * @returns The MeshTxBuilder instance
879
+ */
880
+ invalidBefore = (slot: number) => {
881
+ this.meshTxBuilderBody.validityRange.invalidBefore = slot;
882
+ return this;
883
+ };
884
+
885
+ /**
886
+ * Set the transaction valid interval to be valid only before the slot
887
+ * @param slot The transaction is valid only before this slot
888
+ * @returns The MeshTxBuilder instance
889
+ */
890
+ invalidHereafter = (slot: number) => {
891
+ this.meshTxBuilderBody.validityRange.invalidHereafter = slot;
892
+ return this;
893
+ };
894
+
895
+ /**
896
+ * Add metadata to the transaction
897
+ * @param tag The tag of the metadata
898
+ * @param metadata The metadata in any format
899
+ * @returns The MeshTxBuilder instance
900
+ */
901
+ metadataValue = (tag: string, metadata: any) => {
902
+ const metadataString = JSONBig.stringify(metadata);
903
+ this.meshTxBuilderBody.metadata.push({ tag, metadata: metadataString });
904
+ return this;
905
+ };
906
+
907
+ /**
908
+ * Sign the transaction with the private key
909
+ * @param skeyHex The private key in cborHex (with or without 5820 prefix, i.e. the format when generated from cardano-cli)
910
+ * @returns
911
+ */
912
+ signingKey = (skeyHex: string) => {
913
+ this.meshTxBuilderBody.signingKey.push(skeyHex);
914
+ return this;
915
+ };
916
+
917
+ /**
918
+ * EXPERIMENTAL - Selects utxos to fill output value and puts them into inputs
919
+ * @param extraInputs The inputs already placed into the object will remain, these extra inputs will be used to fill the remaining value needed
920
+ * @param threshold Extra value needed to be selected for, usually for paying fees and min UTxO value of change output
921
+ */
922
+ selectUtxosFrom = (extraInputs: UTxO[], threshold = 5000000) => {
923
+ this.meshTxBuilderBody.extraInputs = extraInputs;
924
+ this.meshTxBuilderBody.selectionThreshold = threshold;
925
+ return this;
926
+ };
927
+
928
+ /**
929
+ * Set the protocol parameters to be used for the transaction other than the default one
930
+ * @param params (Part of) the protocol parameters to be used for the transaction
931
+ * @returns The MeshTxBuilder instance
932
+ */
933
+ protocolParams = (params: Partial<Protocol>) => {
934
+ const updatedParams = { ...DEFAULT_PROTOCOL_PARAMETERS, ...params };
935
+ this._protocolParams = updatedParams;
936
+ return this;
937
+ };
938
+
939
+ protected queueAllLastItem = () => {
940
+ if (this.txOutput) {
941
+ this.meshTxBuilderBody.outputs.push(this.txOutput);
942
+ this.txOutput = undefined;
943
+ }
944
+ if (this.txInQueueItem) {
945
+ this.queueInput();
946
+ }
947
+ if (this.collateralQueueItem) {
948
+ this.meshTxBuilderBody.collaterals.push(this.collateralQueueItem);
949
+ this.collateralQueueItem = undefined;
950
+ }
951
+ if (this.mintItem) {
952
+ this.queueMint();
953
+ }
954
+ if (this.withdrawalItem) {
955
+ this.queueWithdrawal();
956
+ }
957
+ };
958
+
959
+ private queueInput = () => {
960
+ if (!this.txInQueueItem) throw Error("queueInput: Undefined input");
961
+ if (this.txInQueueItem.type === "Script") {
962
+ if (!this.txInQueueItem.scriptTxIn) {
963
+ throw Error(
964
+ "queueInput: Script input does not contain script, datum, or redeemer information"
965
+ );
966
+ } else {
967
+ if (!this.txInQueueItem.scriptTxIn.datumSource)
968
+ throw Error(
969
+ "queueInput: Script input does not contain datum information"
970
+ );
971
+ if (!this.txInQueueItem.scriptTxIn.redeemer)
972
+ throw Error(
973
+ "queueInput: Script input does not contain redeemer information"
974
+ );
975
+ if (!this.txInQueueItem.scriptTxIn.scriptSource)
976
+ throw Error(
977
+ "queueInput: Script input does not contain script information"
978
+ );
979
+ }
980
+ }
981
+ this.meshTxBuilderBody.inputs.push(this.txInQueueItem);
982
+ this.txInQueueItem = undefined;
983
+ };
984
+
985
+ private queueMint = () => {
986
+ if (!this.mintItem) throw Error("queueMint: Undefined mint");
987
+ if (!this.mintItem.scriptSource)
988
+ throw Error("queueMint: Missing mint script information");
989
+ this.meshTxBuilderBody.mints.push(this.mintItem);
990
+ this.mintItem = undefined;
991
+ };
992
+
993
+ private queueWithdrawal = () => {
994
+ if (!this.withdrawalItem)
995
+ throw Error("queueWithdrawal: Undefined withdrawal");
996
+ if ("plutusScriptWithdrawal" in this.withdrawalItem) {
997
+ if (!this.withdrawalItem.plutusScriptWithdrawal.scriptSource) {
998
+ throw Error("queueWithdrawal: Missing withdrawal script information");
999
+ }
1000
+ if (!this.withdrawalItem.plutusScriptWithdrawal.redeemer) {
1001
+ throw Error("queueWithdrawal: Missing withdrawal redeemer information");
1002
+ }
1003
+ }
1004
+ this.meshTxBuilderBody.withdrawals.push(this.withdrawalItem);
1005
+ this.withdrawalItem = undefined;
1006
+ };
1007
+
1008
+ protected castRawDataToJsonString = (rawData: object | string) => {
1009
+ if (typeof rawData === "object") {
1010
+ return JSONBig.stringify(rawData);
1011
+ } else {
1012
+ return rawData as string;
1013
+ }
1014
+ };
1015
+
1016
+ protected castBuilderDataToRedeemer = (
1017
+ redeemer: BuilderData["content"],
1018
+ type: BuilderData["type"] = "Mesh",
1019
+ exUnits = { ...DEFAULT_REDEEMER_BUDGET }
1020
+ ): Redeemer => {
1021
+ let red: Redeemer;
1022
+ let content = redeemer;
1023
+ if (type === "Mesh") {
1024
+ red = {
1025
+ data: {
1026
+ type,
1027
+ content: content as Data,
1028
+ },
1029
+ exUnits,
1030
+ };
1031
+ return red;
1032
+ }
1033
+ if (type === "JSON") {
1034
+ content = this.castRawDataToJsonString(redeemer as object | string);
1035
+ }
1036
+ red = {
1037
+ data: {
1038
+ type,
1039
+ content: content as string,
1040
+ },
1041
+ exUnits,
1042
+ };
1043
+ return red;
1044
+ };
1045
+
1046
+ protected updateRedeemer = (
1047
+ meshTxBuilderBody: MeshTxBuilderBody,
1048
+ txEvaluation: Omit<Action, "data">[]
1049
+ ) => {
1050
+ txEvaluation.forEach((redeemerEvaluation) => {
1051
+ switch (redeemerEvaluation.tag) {
1052
+ case "SPEND": {
1053
+ const input = meshTxBuilderBody.inputs[redeemerEvaluation.index]!;
1054
+ if (input.type == "Script" && input.scriptTxIn.redeemer) {
1055
+ input.scriptTxIn.redeemer.exUnits.mem = Math.floor(
1056
+ redeemerEvaluation.budget.mem * this.txEvaluationMultiplier
1057
+ );
1058
+ input.scriptTxIn.redeemer.exUnits.steps = Math.floor(
1059
+ redeemerEvaluation.budget.steps * this.txEvaluationMultiplier
1060
+ );
1061
+ }
1062
+ break;
1063
+ }
1064
+ case "MINT": {
1065
+ const mint = meshTxBuilderBody.mints[redeemerEvaluation.index]!;
1066
+ if (mint.type == "Plutus" && mint.redeemer) {
1067
+ mint.redeemer.exUnits.mem = Math.floor(
1068
+ redeemerEvaluation.budget.mem * this.txEvaluationMultiplier
1069
+ );
1070
+ mint.redeemer.exUnits.steps = Math.floor(
1071
+ redeemerEvaluation.budget.steps * this.txEvaluationMultiplier
1072
+ );
1073
+ }
1074
+ break;
1075
+ }
1076
+ case "CERT":
1077
+ // TODO
1078
+ break;
1079
+ case "REWARD":
1080
+ // TODO
1081
+ break;
1082
+ }
1083
+ });
1084
+ };
1085
+
1086
+ addUtxosFromSelection = () => {
1087
+ const requiredAssets = this.meshTxBuilderBody.outputs.reduce(
1088
+ (map, output) => {
1089
+ const outputAmount = output.amount;
1090
+ outputAmount.forEach((asset) => {
1091
+ const { unit, quantity } = asset;
1092
+ const existingQuantity = Number(map.get(unit)) || 0;
1093
+ map.set(unit, String(existingQuantity + Number(quantity)));
1094
+ });
1095
+ return map;
1096
+ },
1097
+ new Map<Unit, Quantity>()
1098
+ );
1099
+ this.meshTxBuilderBody.inputs.reduce((map, input) => {
1100
+ const inputAmount = input.txIn.amount;
1101
+ inputAmount?.forEach((asset) => {
1102
+ const { unit, quantity } = asset;
1103
+ const existingQuantity = Number(map.get(unit)) || 0;
1104
+ map.set(unit, String(existingQuantity - Number(quantity)));
1105
+ });
1106
+ return map;
1107
+ }, requiredAssets);
1108
+ this.meshTxBuilderBody.mints.reduce((map, mint) => {
1109
+ const mintAmount: Asset = {
1110
+ unit: mint.policyId + mint.assetName,
1111
+ quantity: String(mint.amount),
1112
+ };
1113
+ const existingQuantity = Number(map.get(mintAmount.unit)) || 0;
1114
+ map.set(
1115
+ mintAmount.unit,
1116
+ String(existingQuantity - Number(mintAmount.quantity))
1117
+ );
1118
+ return map;
1119
+ }, requiredAssets);
1120
+ const selectedInputs = experimentalSelectUtxos(
1121
+ requiredAssets,
1122
+ this.meshTxBuilderBody.extraInputs,
1123
+ this.meshTxBuilderBody.selectionThreshold.toString()
1124
+ );
1125
+ selectedInputs.forEach((input) => {
1126
+ const pubKeyTxIn: PubKeyTxIn = {
1127
+ type: "PubKey",
1128
+ txIn: {
1129
+ txHash: input.input.txHash,
1130
+ txIndex: input.input.outputIndex,
1131
+ amount: input.output.amount,
1132
+ address: input.output.address,
1133
+ },
1134
+ };
1135
+ this.meshTxBuilderBody.inputs.push(pubKeyTxIn);
1136
+ });
1137
+ };
1138
+
1139
+ removeDuplicateInputs = () => {
1140
+ const { inputs } = this.meshTxBuilderBody;
1141
+ const getTxInId = (txIn: TxInParameter): string =>
1142
+ `${txIn.txHash}#${txIn.txIndex}`;
1143
+ const currentTxInIds: string[] = [];
1144
+ const addedInputs: TxIn[] = [];
1145
+ for (let i = 0; i < inputs.length; i += 1) {
1146
+ const currentInput = inputs[i]!;
1147
+ const currentTxInId = getTxInId(currentInput.txIn);
1148
+ if (currentTxInIds.includes(currentTxInId)) {
1149
+ inputs.splice(i, 1);
1150
+ i -= 1;
1151
+ } else {
1152
+ addedInputs.push(currentInput);
1153
+ }
1154
+ }
1155
+ this.meshTxBuilderBody.inputs = addedInputs;
1156
+ };
1157
+
1158
+ emptyTxBuilderBody = () => {
1159
+ this.meshTxBuilderBody = emptyTxBuilderBody();
1160
+ return emptyTxBuilderBody;
1161
+ };
1162
+
1163
+ reset = () => {
1164
+ this.meshTxBuilderBody = emptyTxBuilderBody();
1165
+ this.txEvaluationMultiplier = 1.1;
1166
+ this.txOutput = undefined;
1167
+ this.addingPlutusScriptInput = false;
1168
+ this.plutusSpendingScriptVersion = undefined;
1169
+ this.addingPlutusMint = false;
1170
+ this.plutusMintingScriptVersion = undefined;
1171
+ this.addingPlutusWithdrawal = false;
1172
+ this.plutusWithdrawalScriptVersion = undefined;
1173
+ this._protocolParams = DEFAULT_PROTOCOL_PARAMETERS;
1174
+ this.mintItem = undefined;
1175
+ this.txInQueueItem = undefined;
1176
+ this.withdrawalItem = undefined;
1177
+ this.collateralQueueItem = undefined;
1178
+ this.refScriptTxInQueueItem = undefined;
1179
+ };
1180
+ }