@meshsdk/core-cst 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.
- package/README.md +5 -0
- package/jest.config.js +5 -0
- package/package.json +41 -0
- package/src/cip8/index.ts +24 -0
- package/src/index.ts +16 -0
- package/src/resolvers/index.ts +141 -0
- package/src/serializer/index.ts +678 -0
- package/src/stricahq/index.ts +24 -0
- package/src/types/cardano-sdk.ts +243 -0
- package/src/types/index.ts +2 -0
- package/src/types/signer.ts +7 -0
- package/src/utils/builder.ts +130 -0
- package/src/utils/converter.ts +371 -0
- package/src/utils/deserializer.ts +76 -0
- package/src/utils/encoding.ts +12 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/script-data-hash.ts +87 -0
- package/src/utils/value.ts +61 -0
- package/test/resolvers.test.ts +140 -0
- package/test/utils/converter.test.ts +18 -0
- package/tsconfig.json +5 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { Serialization } from "@cardano-sdk/core";
|
|
2
|
+
import { Ed25519KeyHash } from "@cardano-sdk/crypto";
|
|
3
|
+
import { HexBlob } from "@cardano-sdk/util";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
Asset,
|
|
7
|
+
Data,
|
|
8
|
+
NativeScript,
|
|
9
|
+
PlutusScript,
|
|
10
|
+
Quantity,
|
|
11
|
+
toBytes,
|
|
12
|
+
Unit,
|
|
13
|
+
UTxO,
|
|
14
|
+
} from "@meshsdk/common";
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
Address,
|
|
18
|
+
AssetId,
|
|
19
|
+
AssetName,
|
|
20
|
+
BaseAddress,
|
|
21
|
+
ConstrPlutusData,
|
|
22
|
+
NativeScript as CstNativeScript,
|
|
23
|
+
Datum,
|
|
24
|
+
EnterpriseAddress,
|
|
25
|
+
PlutusData,
|
|
26
|
+
PlutusList,
|
|
27
|
+
PlutusMap,
|
|
28
|
+
PlutusV1Script,
|
|
29
|
+
PlutusV2Script,
|
|
30
|
+
PlutusV3Script,
|
|
31
|
+
PolicyId,
|
|
32
|
+
RequireAllOf,
|
|
33
|
+
RequireAnyOf,
|
|
34
|
+
RequireNOf,
|
|
35
|
+
RequireSignature,
|
|
36
|
+
RequireTimeAfter,
|
|
37
|
+
RequireTimeBefore,
|
|
38
|
+
RewardAddress,
|
|
39
|
+
Script,
|
|
40
|
+
Slot,
|
|
41
|
+
TokenMap,
|
|
42
|
+
TransactionInput,
|
|
43
|
+
TransactionOutput,
|
|
44
|
+
TransactionUnspentOutput,
|
|
45
|
+
Value,
|
|
46
|
+
} from "../types";
|
|
47
|
+
import {
|
|
48
|
+
deserializeDataHash,
|
|
49
|
+
deserializePlutusData,
|
|
50
|
+
deserializePlutusScript,
|
|
51
|
+
deserializeScriptRef,
|
|
52
|
+
deserializeTxHash,
|
|
53
|
+
} from "./deserializer";
|
|
54
|
+
|
|
55
|
+
export const toAddress = (bech32: string): Address =>
|
|
56
|
+
Address.fromBech32(bech32);
|
|
57
|
+
|
|
58
|
+
export const toBaseAddress = (bech32: string): BaseAddress | undefined => {
|
|
59
|
+
return BaseAddress.fromAddress(toAddress(bech32));
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const toEnterpriseAddress = (
|
|
63
|
+
bech32: string,
|
|
64
|
+
): EnterpriseAddress | undefined => {
|
|
65
|
+
return EnterpriseAddress.fromAddress(toAddress(bech32));
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const toRewardAddress = (bech32: string): RewardAddress | undefined =>
|
|
69
|
+
RewardAddress.fromAddress(toAddress(bech32));
|
|
70
|
+
|
|
71
|
+
export const fromTxUnspentOutput = (
|
|
72
|
+
txUnspentOutput: TransactionUnspentOutput,
|
|
73
|
+
): UTxO => {
|
|
74
|
+
const dataHash = txUnspentOutput.output().datum()
|
|
75
|
+
? txUnspentOutput.output().datum()?.toCbor().toString()
|
|
76
|
+
: undefined;
|
|
77
|
+
|
|
78
|
+
const scriptRef = txUnspentOutput.output().scriptRef()
|
|
79
|
+
? txUnspentOutput.output().scriptRef()?.toCbor().toString()
|
|
80
|
+
: undefined;
|
|
81
|
+
|
|
82
|
+
const plutusData = txUnspentOutput.output().datum()?.asInlineData()
|
|
83
|
+
? txUnspentOutput.output().datum()?.asInlineData()?.toCbor().toString()
|
|
84
|
+
: undefined;
|
|
85
|
+
|
|
86
|
+
return <UTxO>{
|
|
87
|
+
input: {
|
|
88
|
+
outputIndex: Number(txUnspentOutput.input().index()),
|
|
89
|
+
txHash: txUnspentOutput.input().transactionId(),
|
|
90
|
+
},
|
|
91
|
+
output: {
|
|
92
|
+
address: txUnspentOutput.output().address().toBech32(),
|
|
93
|
+
amount: fromValue(txUnspentOutput.output().amount()),
|
|
94
|
+
dataHash: dataHash, // todo not sure if correct
|
|
95
|
+
plutusData: plutusData, // todo not sure if correct
|
|
96
|
+
scriptRef: scriptRef, // todo not sure if correct
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const toTxUnspentOutput = (utxo: UTxO) => {
|
|
102
|
+
const txInput = new TransactionInput(
|
|
103
|
+
deserializeTxHash(utxo.input.txHash),
|
|
104
|
+
BigInt(utxo.input.outputIndex),
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const txOutput = new TransactionOutput(
|
|
108
|
+
toAddress(utxo.output.address),
|
|
109
|
+
toValue(utxo.output.amount),
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
if (utxo.output.dataHash !== undefined) {
|
|
113
|
+
txOutput.setDatum(
|
|
114
|
+
Datum.fromCore(deserializeDataHash(utxo.output.dataHash)),
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (utxo.output.plutusData !== undefined) {
|
|
119
|
+
const plutusData = deserializePlutusData(utxo.output.plutusData);
|
|
120
|
+
const datum = new Serialization.Datum(undefined, plutusData);
|
|
121
|
+
txOutput.setDatum(datum);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (utxo.output.scriptRef !== undefined) {
|
|
125
|
+
txOutput.setScriptRef(deserializeScriptRef(utxo.output.scriptRef));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return new TransactionUnspentOutput(txInput, txOutput);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const addressToBech32 = (address: Address): string => {
|
|
132
|
+
return address.toBech32();
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export const fromValue = (value: Value) => {
|
|
136
|
+
const assets: Asset[] = [
|
|
137
|
+
{ unit: "lovelace", quantity: value.coin().toString() },
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
const multiAsset = value.multiasset();
|
|
141
|
+
if (multiAsset !== undefined) {
|
|
142
|
+
const _assets = Array.from(multiAsset.keys());
|
|
143
|
+
for (let i = 0; i < _assets.length; i += 1) {
|
|
144
|
+
const assetId = _assets[i];
|
|
145
|
+
if (assetId !== undefined) {
|
|
146
|
+
const assetQuantity = multiAsset.get(assetId);
|
|
147
|
+
if (assetQuantity !== undefined) {
|
|
148
|
+
assets.push({
|
|
149
|
+
unit: assetId as Unit,
|
|
150
|
+
quantity: assetQuantity.toString() as Quantity,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return assets;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const toScriptRef = (script: PlutusScript | NativeScript): Script => {
|
|
161
|
+
if ("code" in script) {
|
|
162
|
+
const plutusScript = deserializePlutusScript(script.code, script.version);
|
|
163
|
+
if (plutusScript instanceof PlutusV1Script)
|
|
164
|
+
return Script.newPlutusV1Script(plutusScript);
|
|
165
|
+
if (plutusScript instanceof PlutusV2Script)
|
|
166
|
+
return Script.newPlutusV2Script(plutusScript);
|
|
167
|
+
if (plutusScript instanceof PlutusV3Script)
|
|
168
|
+
return Script.newPlutusV3Script(plutusScript);
|
|
169
|
+
}
|
|
170
|
+
return Script.newNativeScript(toNativeScript(script as NativeScript));
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
export const fromScriptRef = (
|
|
174
|
+
scriptRef: string,
|
|
175
|
+
): PlutusScript | NativeScript | undefined => {
|
|
176
|
+
const script = Script.fromCbor(HexBlob(scriptRef));
|
|
177
|
+
|
|
178
|
+
const plutusScriptCodeV3 = script.asPlutusV3()?.toCbor().toString();
|
|
179
|
+
if (plutusScriptCodeV3) {
|
|
180
|
+
return {
|
|
181
|
+
code: plutusScriptCodeV3,
|
|
182
|
+
version: "V3",
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const plutusScriptCodeV2 = script.asPlutusV2()?.toCbor().toString();
|
|
187
|
+
if (plutusScriptCodeV2) {
|
|
188
|
+
return {
|
|
189
|
+
code: plutusScriptCodeV2,
|
|
190
|
+
version: "V2",
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const plutusScriptCodeV1 = script.asPlutusV1()?.toCbor().toString();
|
|
195
|
+
if (plutusScriptCodeV1) {
|
|
196
|
+
return {
|
|
197
|
+
code: plutusScriptCodeV1,
|
|
198
|
+
version: "V1",
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// TODO: implement from native script
|
|
203
|
+
const nativeScript = script.asNative();
|
|
204
|
+
if (!nativeScript) {
|
|
205
|
+
throw new Error("Invalid script");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return fromNativeScript(nativeScript);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export const fromNativeScript = (script: CstNativeScript) => {
|
|
212
|
+
const fromNativeScripts = (scripts: CstNativeScript[]) => {
|
|
213
|
+
const nativeScripts = new Array<NativeScript>();
|
|
214
|
+
|
|
215
|
+
for (let index = 0; index < scripts.length; index += 1) {
|
|
216
|
+
const script = scripts[index];
|
|
217
|
+
if (script) {
|
|
218
|
+
nativeScripts.push(fromNativeScript(script));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return nativeScripts;
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
switch (script.kind()) {
|
|
226
|
+
case RequireAllOf: {
|
|
227
|
+
const scriptAll = script.asScriptAll()!;
|
|
228
|
+
return <NativeScript>{
|
|
229
|
+
type: "all",
|
|
230
|
+
scripts: fromNativeScripts(scriptAll.nativeScripts()),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
case RequireAnyOf: {
|
|
234
|
+
const scriptAny = script.asScriptAny()!;
|
|
235
|
+
return <NativeScript>{
|
|
236
|
+
type: "any",
|
|
237
|
+
scripts: fromNativeScripts(scriptAny.nativeScripts()),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
case RequireNOf: {
|
|
241
|
+
const scriptNOfK = script.asScriptNOfK()!;
|
|
242
|
+
return <NativeScript>{
|
|
243
|
+
type: "atLeast",
|
|
244
|
+
required: scriptNOfK.required(),
|
|
245
|
+
scripts: fromNativeScripts(scriptNOfK.nativeScripts()),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
case RequireTimeAfter: {
|
|
249
|
+
const timelockStart = script.asTimelockStart()!;
|
|
250
|
+
return <NativeScript>{
|
|
251
|
+
type: "after",
|
|
252
|
+
slot: timelockStart.slot().toString(),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
case RequireTimeBefore: {
|
|
256
|
+
const timelockExpiry = script.asTimelockExpiry()!;
|
|
257
|
+
return <NativeScript>{
|
|
258
|
+
type: "before",
|
|
259
|
+
slot: timelockExpiry.slot().toString(),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
case RequireSignature: {
|
|
263
|
+
const scriptPubkey = script.asScriptPubkey()!;
|
|
264
|
+
return <NativeScript>{
|
|
265
|
+
type: "sig",
|
|
266
|
+
keyHash: scriptPubkey.keyHash().toString(),
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
default:
|
|
270
|
+
throw new Error(`Script Kind: ${script.kind()}, is not supported`);
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
export const toNativeScript = (script: NativeScript) => {
|
|
275
|
+
const toNativeScripts = (scripts: NativeScript[]) => {
|
|
276
|
+
const nativeScripts: CstNativeScript[] = [];
|
|
277
|
+
|
|
278
|
+
scripts.forEach((script) => {
|
|
279
|
+
nativeScripts.push(toNativeScript(script));
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
return nativeScripts;
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
switch (script.type) {
|
|
286
|
+
case "all":
|
|
287
|
+
return CstNativeScript.newScriptAll(
|
|
288
|
+
new Serialization.ScriptAll(toNativeScripts(script.scripts)),
|
|
289
|
+
);
|
|
290
|
+
case "any":
|
|
291
|
+
return CstNativeScript.newScriptAny(
|
|
292
|
+
new Serialization.ScriptAny(toNativeScripts(script.scripts)),
|
|
293
|
+
);
|
|
294
|
+
case "atLeast":
|
|
295
|
+
return CstNativeScript.newScriptNOfK(
|
|
296
|
+
new Serialization.ScriptNOfK(
|
|
297
|
+
toNativeScripts(script.scripts),
|
|
298
|
+
script.required,
|
|
299
|
+
),
|
|
300
|
+
);
|
|
301
|
+
case "after":
|
|
302
|
+
return CstNativeScript.newTimelockStart(
|
|
303
|
+
new Serialization.TimelockStart(Slot(parseInt(script.slot))),
|
|
304
|
+
);
|
|
305
|
+
case "before":
|
|
306
|
+
return CstNativeScript.newTimelockExpiry(
|
|
307
|
+
new Serialization.TimelockExpiry(Slot(parseInt(script.slot))),
|
|
308
|
+
);
|
|
309
|
+
case "sig":
|
|
310
|
+
return CstNativeScript.newScriptPubkey(
|
|
311
|
+
new Serialization.ScriptPubkey(
|
|
312
|
+
Ed25519KeyHash.fromBytes(toBytes(script.keyHash)).hex(),
|
|
313
|
+
),
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
export const toPlutusData = (data: Data): PlutusData => {
|
|
319
|
+
const toPlutusList = (data: Data[]) => {
|
|
320
|
+
const plutusList = new PlutusList();
|
|
321
|
+
data.forEach((element) => {
|
|
322
|
+
plutusList.add(toPlutusData(element));
|
|
323
|
+
});
|
|
324
|
+
return plutusList;
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
switch (typeof data) {
|
|
328
|
+
case "string":
|
|
329
|
+
return PlutusData.newBytes(toBytes(data));
|
|
330
|
+
case "number":
|
|
331
|
+
return PlutusData.newInteger(BigInt(data));
|
|
332
|
+
case "bigint":
|
|
333
|
+
return PlutusData.newInteger(BigInt(data));
|
|
334
|
+
case "object":
|
|
335
|
+
if (data instanceof Array) {
|
|
336
|
+
const plutusList = toPlutusList(data);
|
|
337
|
+
return PlutusData.newList(plutusList);
|
|
338
|
+
} else if (data instanceof Map) {
|
|
339
|
+
const plutusMap = new PlutusMap();
|
|
340
|
+
data.forEach((value, key) => {
|
|
341
|
+
plutusMap.insert(toPlutusData(key), toPlutusData(value));
|
|
342
|
+
});
|
|
343
|
+
return PlutusData.newMap(plutusMap);
|
|
344
|
+
} else {
|
|
345
|
+
return PlutusData.newConstrPlutusData(
|
|
346
|
+
new ConstrPlutusData(
|
|
347
|
+
BigInt(data.alternative),
|
|
348
|
+
toPlutusList(data.fields),
|
|
349
|
+
),
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
export const toValue = (assets: Asset[]) => {
|
|
356
|
+
const multiAsset: TokenMap = new Map();
|
|
357
|
+
assets
|
|
358
|
+
.filter((asset) => asset.unit !== "lovelace")
|
|
359
|
+
.forEach((asset) => {
|
|
360
|
+
multiAsset.set(AssetId(asset.unit), BigInt(asset.quantity));
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
const lovelace = assets.find((asset) => asset.unit === "lovelace");
|
|
364
|
+
const value = new Value(BigInt(lovelace ? lovelace.quantity : 0));
|
|
365
|
+
|
|
366
|
+
if (assets.length > 1 || !lovelace) {
|
|
367
|
+
value.setMultiasset(multiAsset);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return value;
|
|
371
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { TxCBOR } from "@cardano-sdk/core";
|
|
2
|
+
import { Ed25519KeyHashHex } from "@cardano-sdk/crypto";
|
|
3
|
+
import { HexBlob } from "@cardano-sdk/util";
|
|
4
|
+
|
|
5
|
+
import { LanguageVersion, toBytes } from "@meshsdk/common";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
Address,
|
|
9
|
+
DatumHash,
|
|
10
|
+
Ed25519KeyHash,
|
|
11
|
+
NativeScript,
|
|
12
|
+
PlutusData,
|
|
13
|
+
PlutusV1Script,
|
|
14
|
+
PlutusV2Script,
|
|
15
|
+
PlutusV3Script,
|
|
16
|
+
Script,
|
|
17
|
+
ScriptHash,
|
|
18
|
+
Transaction,
|
|
19
|
+
TransactionId,
|
|
20
|
+
TransactionUnspentOutput,
|
|
21
|
+
Value,
|
|
22
|
+
} from "../types";
|
|
23
|
+
|
|
24
|
+
export const deserializeAddress = (address: string): Address => {
|
|
25
|
+
const _address = Address.fromString(address);
|
|
26
|
+
if (_address === null) throw new Error("Invalid address");
|
|
27
|
+
return _address;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const deserializeEd25519KeyHash = (ed25519KeyHash: string) =>
|
|
31
|
+
Ed25519KeyHash.fromBytes(toBytes(ed25519KeyHash));
|
|
32
|
+
|
|
33
|
+
export const deserializeDataHash = (dataHash: string): DatumHash =>
|
|
34
|
+
DatumHash.fromHexBlob(HexBlob(dataHash));
|
|
35
|
+
|
|
36
|
+
export const deserializePlutusData = (plutusData: string): PlutusData =>
|
|
37
|
+
PlutusData.fromCbor(HexBlob(plutusData));
|
|
38
|
+
|
|
39
|
+
export const deserializePlutusScript = (
|
|
40
|
+
plutusScript: string,
|
|
41
|
+
version: LanguageVersion,
|
|
42
|
+
): PlutusV1Script | PlutusV2Script | PlutusV3Script => {
|
|
43
|
+
switch (version) {
|
|
44
|
+
case "V1":
|
|
45
|
+
return PlutusV1Script.fromCbor(HexBlob(plutusScript));
|
|
46
|
+
case "V2":
|
|
47
|
+
return PlutusV2Script.fromCbor(HexBlob(plutusScript));
|
|
48
|
+
case "V3":
|
|
49
|
+
return PlutusV3Script.fromCbor(HexBlob(plutusScript));
|
|
50
|
+
default:
|
|
51
|
+
throw new Error("Invalid Plutus script version");
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const deserializeNativeScript = (nativeScript: string): NativeScript =>
|
|
56
|
+
NativeScript.fromCbor(HexBlob(nativeScript));
|
|
57
|
+
|
|
58
|
+
export const deserializeScriptHash = (scriptHash: string) =>
|
|
59
|
+
ScriptHash.fromEd25519KeyHashHex(Ed25519KeyHashHex(scriptHash));
|
|
60
|
+
|
|
61
|
+
export const deserializeScriptRef = (scriptRef: string): Script =>
|
|
62
|
+
Script.fromCbor(HexBlob(scriptRef));
|
|
63
|
+
|
|
64
|
+
export const deserializeTxUnspentOutput = (
|
|
65
|
+
txUnspentOutput: string,
|
|
66
|
+
): TransactionUnspentOutput =>
|
|
67
|
+
TransactionUnspentOutput.fromCbor(HexBlob(txUnspentOutput));
|
|
68
|
+
|
|
69
|
+
export const deserializeValue = (value: string): Value =>
|
|
70
|
+
Value.fromCbor(HexBlob(value));
|
|
71
|
+
|
|
72
|
+
export const deserializeTx = (tx: string): Transaction =>
|
|
73
|
+
Transaction.fromCbor(TxCBOR(tx));
|
|
74
|
+
|
|
75
|
+
export const deserializeTxHash = (txHash: string): TransactionId =>
|
|
76
|
+
TransactionId.fromHexBlob(HexBlob(txHash));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { HexBlob } from "@cardano-sdk/util";
|
|
2
|
+
|
|
3
|
+
export const bytesToHex = (bytes: Uint8Array): HexBlob =>
|
|
4
|
+
Buffer.from(bytes).toString("hex") as HexBlob;
|
|
5
|
+
|
|
6
|
+
export const hexToBytes = (hex: HexBlob): Uint8Array => Buffer.from(hex, "hex");
|
|
7
|
+
|
|
8
|
+
export const utf8ToBytes = (str: string): Uint8Array =>
|
|
9
|
+
Buffer.from(str, "utf8");
|
|
10
|
+
|
|
11
|
+
export const utf8ToHex = (str: string): HexBlob =>
|
|
12
|
+
Buffer.from(str, "utf8").toString("hex") as HexBlob;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/* eslint-disable unicorn/number-literal-case */
|
|
2
|
+
import { Cardano, Serialization } from "@cardano-sdk/core";
|
|
3
|
+
import * as Crypto from "@cardano-sdk/crypto";
|
|
4
|
+
import { Hash32ByteBase16 } from "@cardano-sdk/crypto";
|
|
5
|
+
import { HexBlob } from "@cardano-sdk/util";
|
|
6
|
+
|
|
7
|
+
const CBOR_EMPTY_LIST = new Uint8Array([0x80]);
|
|
8
|
+
const CBOR_EMPTY_MAP = new Uint8Array([0xa0]);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Encodes an array of CBOR-encodable objects into a CBOR format.
|
|
12
|
+
*
|
|
13
|
+
* Each object in the array is converted to its CBOR representation and then written into a
|
|
14
|
+
* CBOR array.
|
|
15
|
+
*
|
|
16
|
+
* @param items An array of objects that can be encoded into CBOR.
|
|
17
|
+
* @returns A `Uint8Array` containing the CBOR-encoded objects.
|
|
18
|
+
*/
|
|
19
|
+
const getCborEncodedArray = <T extends { toCbor: () => HexBlob }>(
|
|
20
|
+
items: T[],
|
|
21
|
+
): Uint8Array => {
|
|
22
|
+
const writer = new Serialization.CborWriter();
|
|
23
|
+
|
|
24
|
+
writer.writeStartArray(items.length);
|
|
25
|
+
|
|
26
|
+
for (const item of items) {
|
|
27
|
+
writer.writeEncodedValue(Buffer.from(item.toCbor(), "hex"));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return writer.encode();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Computes the hash of script data in a transaction, including redeemers, datums, and cost models.
|
|
35
|
+
*
|
|
36
|
+
* This function takes arrays of redeemers and datums, along with cost models, and encodes
|
|
37
|
+
* them in a CBOR (Concise Binary Object Representation) format. The encoded data is then
|
|
38
|
+
* hashed using the Blake2b hashing algorithm to produce a 32-byte hash. This hash is
|
|
39
|
+
* representative of the script data in a transaction on the Cardano blockchain.
|
|
40
|
+
*
|
|
41
|
+
* @param costModels The cost models for script execution.
|
|
42
|
+
* @param redemeers The redeemers in the transaction. If not present or empty, the function may return undefined.
|
|
43
|
+
* @param datums The datums in the transaction.
|
|
44
|
+
* @returns The hashed script data, or undefined if no redeemers are provided.
|
|
45
|
+
*/
|
|
46
|
+
export const hashScriptData = (
|
|
47
|
+
costModels: Serialization.Costmdls,
|
|
48
|
+
redemeers?: Serialization.Redeemer[],
|
|
49
|
+
datums?: Serialization.PlutusData[],
|
|
50
|
+
): Crypto.Hash32ByteBase16 | undefined => {
|
|
51
|
+
const writer = new Serialization.CborWriter();
|
|
52
|
+
|
|
53
|
+
if (datums && datums.length > 0 && (!redemeers || redemeers.length === 0)) {
|
|
54
|
+
/*
|
|
55
|
+
; Note that in the case that a transaction includes datums but does not
|
|
56
|
+
; include any redeemers, the script data format becomes (in hex):
|
|
57
|
+
; [ 80 | datums | A0 ]
|
|
58
|
+
; corresponding to a CBOR empty list and an empty map).
|
|
59
|
+
*/
|
|
60
|
+
writer.writeEncodedValue(CBOR_EMPTY_LIST);
|
|
61
|
+
writer.writeEncodedValue(getCborEncodedArray(datums));
|
|
62
|
+
writer.writeEncodedValue(CBOR_EMPTY_MAP);
|
|
63
|
+
} else {
|
|
64
|
+
if (!redemeers || redemeers.length === 0) return undefined;
|
|
65
|
+
/*
|
|
66
|
+
; script data format:
|
|
67
|
+
; [ redeemers | datums | language views ]
|
|
68
|
+
; The redeemers are exactly the data present in the transaction witness set.
|
|
69
|
+
; Similarly for the datums, if present. If no datums are provided, the middle
|
|
70
|
+
; field is an empty string.
|
|
71
|
+
*/
|
|
72
|
+
writer.writeEncodedValue(getCborEncodedArray(redemeers));
|
|
73
|
+
|
|
74
|
+
if (datums && datums.length > 0)
|
|
75
|
+
writer.writeEncodedValue(getCborEncodedArray(datums));
|
|
76
|
+
|
|
77
|
+
writer.writeEncodedValue(
|
|
78
|
+
Buffer.from(costModels.languageViewsEncoding(), "hex"),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return Hash32ByteBase16.fromHexBlob(
|
|
83
|
+
HexBlob.fromBytes(
|
|
84
|
+
Crypto.blake2b(Crypto.blake2b.BYTES).update(writer.encode()).digest(),
|
|
85
|
+
),
|
|
86
|
+
);
|
|
87
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { TokenMap, Value } from "../types";
|
|
2
|
+
|
|
3
|
+
export function mergeValue(a: Value, b: Value): Value {
|
|
4
|
+
const ma = a.multiasset() ?? new Map();
|
|
5
|
+
b.multiasset()?.forEach((v, k) => {
|
|
6
|
+
const newVal = (ma.get(k) ?? 0n) + v;
|
|
7
|
+
if (newVal == 0n) {
|
|
8
|
+
ma.delete(k);
|
|
9
|
+
} else {
|
|
10
|
+
ma.set(k, newVal);
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
return new Value(
|
|
14
|
+
BigInt(a.coin()) + BigInt(b.coin()),
|
|
15
|
+
ma.size > 0 ? ma : undefined,
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function negateValue(v: Value): Value {
|
|
20
|
+
const entries = v.multiasset()?.entries();
|
|
21
|
+
const tokenMap: TokenMap = new Map();
|
|
22
|
+
if (entries) {
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
tokenMap.set(entry[0], -entry[1]);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return new Value(-v.coin(), tokenMap);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function subValue(a: Value, b: Value): Value {
|
|
31
|
+
return mergeValue(a, negateValue(b));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function negatives(v: Value): Value {
|
|
35
|
+
const entries = v.multiasset()?.entries();
|
|
36
|
+
const coin = v.coin() < 0n ? v.coin() : 0n;
|
|
37
|
+
const tokenMap: TokenMap = new Map();
|
|
38
|
+
if (entries) {
|
|
39
|
+
for (const entry of entries) {
|
|
40
|
+
if (entry[1] < 0n) {
|
|
41
|
+
tokenMap.set(entry[0], entry[1]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return new Value(coin, tokenMap);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function assetTypes(v: Value): number {
|
|
49
|
+
let count = v.coin() == 0n ? 0 : 1;
|
|
50
|
+
const entries = v.multiasset();
|
|
51
|
+
if (entries) {
|
|
52
|
+
entries.forEach(() => {
|
|
53
|
+
count += 1;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return count;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function empty(v: Value): boolean {
|
|
60
|
+
return assetTypes(v) == 0;
|
|
61
|
+
}
|