@evolution-sdk/scalus-uplc 0.0.1

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,3 @@
1
+ import * as TransactionBuilder from "@evolution-sdk/evolution/sdk/builders/TransactionBuilder";
2
+ export declare function makeEvaluator(): TransactionBuilder.Evaluator;
3
+ //# sourceMappingURL=Evaluator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Evaluator.d.ts","sourceRoot":"","sources":["../src/Evaluator.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,kBAAkB,MAAM,0DAA0D,CAAA;AAiD9F,wBAAgB,aAAa,IAAI,kBAAkB,CAAC,SAAS,CAqG5D"}
@@ -0,0 +1,118 @@
1
+ import * as Bytes from "@evolution-sdk/evolution/Bytes";
2
+ import * as CBOR from "@evolution-sdk/evolution/CBOR";
3
+ import * as Redeemer from "@evolution-sdk/evolution/Redeemer";
4
+ import * as Script from "@evolution-sdk/evolution/Script";
5
+ import * as ScriptRef from "@evolution-sdk/evolution/ScriptRef";
6
+ import * as TransactionBuilder from "@evolution-sdk/evolution/sdk/builders/TransactionBuilder";
7
+ import * as Transaction from "@evolution-sdk/evolution/Transaction";
8
+ import * as TransactionInput from "@evolution-sdk/evolution/TransactionInput";
9
+ import * as TxOut from "@evolution-sdk/evolution/TxOut";
10
+ import { Effect, Schema } from "effect";
11
+ import * as Scalus from "scalus";
12
+ /**
13
+ * Build CBOR-encoded map of TransactionInput → TransactionOutput from UTxOs.
14
+ *
15
+ * Uses FromCDDL schemas to get CBOR values directly, avoiding wasteful
16
+ * bytes → CBOR → bytes roundtrip encoding.
17
+ */
18
+ function buildUtxoMapCBOR(utxos) {
19
+ const utxoMap = new Map();
20
+ for (const utxo of utxos) {
21
+ // Use FromCDDL to get CBOR values directly (no double encoding)
22
+ const txInput = new TransactionInput.TransactionInput({
23
+ transactionId: utxo.transactionId,
24
+ index: utxo.index
25
+ });
26
+ const inputCBOR = Schema.encodeSync(TransactionInput.FromCDDL)(txInput);
27
+ const scriptRef = utxo.scriptRef ? new ScriptRef.ScriptRef({ bytes: Script.toCBOR(utxo.scriptRef) }) : undefined;
28
+ const txOut = new TxOut.TransactionOutput({
29
+ address: utxo.address,
30
+ assets: utxo.assets,
31
+ datumOption: utxo.datumOption,
32
+ scriptRef
33
+ });
34
+ const outputCBOR = Schema.encodeSync(TxOut.FromCDDL)(txOut);
35
+ utxoMap.set(inputCBOR, outputCBOR);
36
+ }
37
+ return CBOR.toCBORBytes(utxoMap, CBOR.CML_DEFAULT_OPTIONS);
38
+ }
39
+ function decodeCostModels(costModels) {
40
+ // Scalus expects a flattened representation of the cost models as number arrays
41
+ const plutusV1 = costModels.PlutusV1.costs.map((c) => Number(c));
42
+ const plutusV2 = costModels.PlutusV2.costs.map((c) => Number(c));
43
+ const plutusV3 = costModels.PlutusV3.costs.map((c) => Number(c));
44
+ return [plutusV1, plutusV2, plutusV3];
45
+ }
46
+ export function makeEvaluator() {
47
+ return {
48
+ evaluate: (tx, additionalUtxos, context) => Effect.gen(function* () {
49
+ yield* Effect.logDebug("[Scalus UPLC] Starting evaluation");
50
+ // Serialize transaction to CBOR bytes
51
+ const txBytes = Transaction.toCBORBytes(tx);
52
+ yield* Effect.logDebug(`[Scalus UPLC] Transaction CBOR bytes: ${txBytes.length}`);
53
+ const utxos = additionalUtxos ?? [];
54
+ yield* Effect.logDebug(`[Scalus UPLC] Additional UTxOs: ${utxos.length}`);
55
+ // Build UTxO map CBOR
56
+ const utxosBytes = buildUtxoMapCBOR(utxos);
57
+ yield* Effect.logDebug(`[Scalus UPLC] UTxO map CBOR bytes: ${utxosBytes.length}`);
58
+ yield* Effect.logDebug(`[Scalus UPLC] UTxO map CBOR hex: ${Bytes.toHex(utxosBytes)}`);
59
+ const { slotLength, zeroSlot, zeroTime } = context.slotConfig;
60
+ yield* Effect.logDebug(`[Scalus UPLC] Slot config - zeroTime: ${zeroTime}, zeroSlot: ${zeroSlot}, slotLength: ${slotLength}`);
61
+ const costModels = decodeCostModels(context.costModels);
62
+ yield* Effect.logDebug(`[Scalus UPLC] Cost models - V1: ${costModels[0].length}, V2: ${costModels[1].length}, V3: ${costModels[2].length} costs`);
63
+ yield* Effect.logDebug(`[Scalus UPLC] Max execution - steps: ${context.maxTxExSteps}, mem: ${context.maxTxExMem}`);
64
+ // Scalus-specific slot config
65
+ const slotConfig = new Scalus.SlotConfig(Number(zeroTime), Number(zeroSlot), slotLength);
66
+ yield* Effect.logDebug("[Scalus UPLC] Calling evalPlutusScripts...");
67
+ const redeemers = yield* Effect.try({
68
+ try: () => Scalus.Scalus.evalPlutusScripts(txBytes, utxosBytes, slotConfig, costModels),
69
+ catch: (error) => {
70
+ // Scalus error messages and evaluation logs, if any, are available to form an exception
71
+ const errorObj = error;
72
+ const msg = errorObj?.message ?? "Unknown evaluation error";
73
+ return new TransactionBuilder.EvaluationError({
74
+ cause: error,
75
+ message: msg,
76
+ failures: []
77
+ });
78
+ }
79
+ });
80
+ yield* Effect.logDebug(`[Scalus UPLC] Evaluation successful - ${redeemers.length} redeemer(s) returned`);
81
+ // Check if redeemers array is empty
82
+ if (redeemers.length === 0) {
83
+ return yield* new TransactionBuilder.EvaluationError({
84
+ message: "Scalus evaluation returned no redeemers",
85
+ failures: []
86
+ });
87
+ }
88
+ // Transform Scalus redeemers to Evolution format and check for zero execution units
89
+ const evalRedeemers = [];
90
+ for (const r of redeemers) {
91
+ const mem = BigInt(r.budget.memory);
92
+ const steps = BigInt(r.budget.steps);
93
+ // Check if execution units are zero (indicates evaluation failure)
94
+ if (mem === 0n && steps === 0n) {
95
+ return yield* Effect.fail(new TransactionBuilder.EvaluationError({
96
+ message: `Scalus evaluation returned zero execution units for redeemer ${r.tag}:${r.index}`,
97
+ failures: []
98
+ }));
99
+ }
100
+ const tagMap = {
101
+ Spend: "spend",
102
+ Mint: "mint",
103
+ Cert: "cert",
104
+ Reward: "reward",
105
+ Voting: "vote",
106
+ Proposing: "propose"
107
+ };
108
+ evalRedeemers.push({
109
+ redeemer_tag: tagMap[r.tag] || "spend",
110
+ redeemer_index: r.index,
111
+ ex_units: new Redeemer.ExUnits({ mem, steps })
112
+ });
113
+ }
114
+ return evalRedeemers;
115
+ })
116
+ };
117
+ }
118
+ //# sourceMappingURL=Evaluator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Evaluator.js","sourceRoot":"","sources":["../src/Evaluator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Browser entry point - not implemented in rough draft
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ import type * as TransactionBuilder from "@evolution-sdk/evolution/sdk/builders/TransactionBuilder";
7
+ /**
8
+ * Create a Scalus UPLC evaluator instance for browser environments.
9
+ *
10
+ * @throws Error - Browser support not yet implemented
11
+ */
12
+ export declare function createScalusEvaluator(): TransactionBuilder.Evaluator;
13
+ //# sourceMappingURL=index.browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.browser.d.ts","sourceRoot":"","sources":["../src/index.browser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,KAAK,kBAAkB,MAAM,0DAA0D,CAAA;AAEnG;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,kBAAkB,CAAC,SAAS,CAEpE"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Browser entry point - not implemented in rough draft
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ /**
7
+ * Create a Scalus UPLC evaluator instance for browser environments.
8
+ *
9
+ * @throws Error - Browser support not yet implemented
10
+ */
11
+ export function createScalusEvaluator() {
12
+ throw new Error("Browser support not yet implemented for Scalus UPLC evaluator");
13
+ }
14
+ //# sourceMappingURL=index.browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.browser.js","sourceRoot":"","sources":["../src/index.browser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;GAIG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAA;AAClF,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Create a Scalus UPLC evaluator instance.
3
+ *
4
+ * @returns A TransactionBuilder.Evaluator that uses Scalus for script evaluation
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { createScalusEvaluator } from "@evolution-sdk/scalus-uplc"
9
+ *
10
+ * const evaluator = createScalusEvaluator()
11
+ * const redeemers = await Effect.runPromise(evaluator.evaluate(tx, utxos, context))
12
+ * ```
13
+ */
14
+ export declare const createScalusEvaluator: import("@evolution-sdk/evolution/sdk/builders/TransactionBuilder").Evaluator;
15
+ //# sourceMappingURL=index.node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.node.d.ts","sourceRoot":"","sources":["../src/index.node.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,8EAAkB,CAAA"}
@@ -0,0 +1,16 @@
1
+ import { makeEvaluator } from "./Evaluator.js";
2
+ /**
3
+ * Create a Scalus UPLC evaluator instance.
4
+ *
5
+ * @returns A TransactionBuilder.Evaluator that uses Scalus for script evaluation
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { createScalusEvaluator } from "@evolution-sdk/scalus-uplc"
10
+ *
11
+ * const evaluator = createScalusEvaluator()
12
+ * const redeemers = await Effect.runPromise(evaluator.evaluate(tx, utxos, context))
13
+ * ```
14
+ */
15
+ export const createScalusEvaluator = makeEvaluator();
16
+ //# sourceMappingURL=index.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.node.js","sourceRoot":"","sources":["../src/index.node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE9C;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,aAAa,EAAE,CAAA"}
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "@evolution-sdk/scalus-uplc",
3
+ "version": "0.0.1",
4
+ "description": "Scalus UPLC evaluator adapter for Evolution SDK",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "sideEffects": [],
10
+ "tags": [
11
+ "typescript",
12
+ "cardano",
13
+ "scalus",
14
+ "uplc",
15
+ "evaluator"
16
+ ],
17
+ "exports": {
18
+ ".": {
19
+ "types": "./src/index.node.ts",
20
+ "node": "./src/index.node.ts",
21
+ "default": "./src/index.node.ts"
22
+ },
23
+ "./package.json": "./package.json"
24
+ },
25
+ "files": [
26
+ "src/**/*.ts",
27
+ "dist/**/*.js",
28
+ "dist/**/*.js.map",
29
+ "dist/**/*.d.ts",
30
+ "dist/**/*.d.ts.map"
31
+ ],
32
+ "scripts": {
33
+ "build": "tsc -b tsconfig.build.json",
34
+ "dev": "tsc -b tsconfig.build.json --watch",
35
+ "type-check": "tsc --noEmit",
36
+ "lint": "eslint \"src/**/*.{ts,mjs}\"",
37
+ "clean": "rm -rf dist .turbo .tsbuildinfo"
38
+ },
39
+ "dependencies": {
40
+ "effect": "^3.19.3",
41
+ "scalus": "^0.14.2"
42
+ },
43
+ "peerDependencies": {
44
+ "@evolution-sdk/evolution": "workspace:*"
45
+ },
46
+ "devDependencies": {
47
+ "typescript": "^5.9.2"
48
+ },
49
+ "keywords": [
50
+ "cardano",
51
+ "blockchain",
52
+ "scalus",
53
+ "uplc",
54
+ "evaluator",
55
+ "typescript",
56
+ "effect"
57
+ ],
58
+ "homepage": "https://github.com/IntersectMBO/evolution-sdk",
59
+ "repository": {
60
+ "type": "git",
61
+ "url": "git+https://github.com/IntersectMBO/evolution-sdk.git",
62
+ "directory": "packages/scalus-uplc"
63
+ },
64
+ "bugs": {
65
+ "url": "https://github.com/IntersectMBO/evolution-sdk/issues"
66
+ },
67
+ "license": "MIT",
68
+ "publishConfig": {
69
+ "access": "public",
70
+ "exports": {
71
+ ".": {
72
+ "node": {
73
+ "types": "./dist/index.node.d.ts",
74
+ "default": "./dist/index.node.js"
75
+ },
76
+ "default": {
77
+ "types": "./dist/index.node.d.ts",
78
+ "default": "./dist/index.node.js"
79
+ }
80
+ },
81
+ "./package.json": "./package.json"
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,157 @@
1
+ import * as Bytes from "@evolution-sdk/evolution/Bytes"
2
+ import * as CBOR from "@evolution-sdk/evolution/CBOR"
3
+ import type * as CostModel from "@evolution-sdk/evolution/CostModel"
4
+ import * as Redeemer from "@evolution-sdk/evolution/Redeemer"
5
+ import * as Script from "@evolution-sdk/evolution/Script"
6
+ import * as ScriptRef from "@evolution-sdk/evolution/ScriptRef"
7
+ import * as TransactionBuilder from "@evolution-sdk/evolution/sdk/builders/TransactionBuilder"
8
+ import type * as EvalRedeemer from "@evolution-sdk/evolution/sdk/EvalRedeemer"
9
+ import * as Transaction from "@evolution-sdk/evolution/Transaction"
10
+ import * as TransactionInput from "@evolution-sdk/evolution/TransactionInput"
11
+ import * as TxOut from "@evolution-sdk/evolution/TxOut"
12
+ import type * as UTxO from "@evolution-sdk/evolution/UTxO"
13
+ import { Effect, Schema } from "effect"
14
+ import * as Scalus from "scalus"
15
+
16
+ /**
17
+ * Build CBOR-encoded map of TransactionInput → TransactionOutput from UTxOs.
18
+ *
19
+ * Uses FromCDDL schemas to get CBOR values directly, avoiding wasteful
20
+ * bytes → CBOR → bytes roundtrip encoding.
21
+ */
22
+ function buildUtxoMapCBOR(utxos: ReadonlyArray<UTxO.UTxO>): Uint8Array {
23
+ const utxoMap = new Map<CBOR.CBOR, CBOR.CBOR>()
24
+
25
+ for (const utxo of utxos) {
26
+ // Use FromCDDL to get CBOR values directly (no double encoding)
27
+ const txInput = new TransactionInput.TransactionInput({
28
+ transactionId: utxo.transactionId,
29
+ index: utxo.index
30
+ })
31
+ const inputCBOR = Schema.encodeSync(TransactionInput.FromCDDL)(txInput)
32
+
33
+ const scriptRef = utxo.scriptRef ? new ScriptRef.ScriptRef({ bytes: Script.toCBOR(utxo.scriptRef) }) : undefined
34
+ const txOut = new TxOut.TransactionOutput({
35
+ address: utxo.address,
36
+ assets: utxo.assets,
37
+ datumOption: utxo.datumOption,
38
+ scriptRef
39
+ })
40
+ const outputCBOR = Schema.encodeSync(TxOut.FromCDDL)(txOut)
41
+
42
+ utxoMap.set(inputCBOR, outputCBOR)
43
+ }
44
+
45
+ return CBOR.toCBORBytes(utxoMap, CBOR.CML_DEFAULT_OPTIONS)
46
+ }
47
+
48
+ function decodeCostModels(costModels: CostModel.CostModels): Array<Array<number>> {
49
+ // Scalus expects a flattened representation of the cost models as number arrays
50
+ const plutusV1 = costModels.PlutusV1.costs.map((c: bigint) => Number(c))
51
+ const plutusV2 = costModels.PlutusV2.costs.map((c: bigint) => Number(c))
52
+ const plutusV3 = costModels.PlutusV3.costs.map((c: bigint) => Number(c))
53
+ return [plutusV1, plutusV2, plutusV3]
54
+ }
55
+
56
+ export function makeEvaluator(): TransactionBuilder.Evaluator {
57
+ return {
58
+ evaluate: (
59
+ tx: Transaction.Transaction,
60
+ additionalUtxos: ReadonlyArray<UTxO.UTxO> | undefined,
61
+ context: TransactionBuilder.EvaluationContext
62
+ ) =>
63
+ Effect.gen(function* () {
64
+ yield* Effect.logDebug("[Scalus UPLC] Starting evaluation")
65
+
66
+ // Serialize transaction to CBOR bytes
67
+ const txBytes = Transaction.toCBORBytes(tx)
68
+
69
+ yield* Effect.logDebug(`[Scalus UPLC] Transaction CBOR bytes: ${txBytes.length}`)
70
+
71
+ const utxos = additionalUtxos ?? []
72
+ yield* Effect.logDebug(`[Scalus UPLC] Additional UTxOs: ${utxos.length}`)
73
+
74
+ // Build UTxO map CBOR
75
+ const utxosBytes = buildUtxoMapCBOR(utxos)
76
+ yield* Effect.logDebug(`[Scalus UPLC] UTxO map CBOR bytes: ${utxosBytes.length}`)
77
+ yield* Effect.logDebug(`[Scalus UPLC] UTxO map CBOR hex: ${Bytes.toHex(utxosBytes)}`)
78
+
79
+ const { slotLength, zeroSlot, zeroTime } = context.slotConfig
80
+
81
+ yield* Effect.logDebug(
82
+ `[Scalus UPLC] Slot config - zeroTime: ${zeroTime}, zeroSlot: ${zeroSlot}, slotLength: ${slotLength}`
83
+ )
84
+
85
+ const costModels: Array<Array<number>> = decodeCostModels(context.costModels)
86
+ yield* Effect.logDebug(
87
+ `[Scalus UPLC] Cost models - V1: ${costModels[0].length}, V2: ${costModels[1].length}, V3: ${costModels[2].length} costs`
88
+ )
89
+ yield* Effect.logDebug(
90
+ `[Scalus UPLC] Max execution - steps: ${context.maxTxExSteps}, mem: ${context.maxTxExMem}`
91
+ )
92
+
93
+ // Scalus-specific slot config
94
+ const slotConfig = new Scalus.SlotConfig(Number(zeroTime), Number(zeroSlot), slotLength)
95
+
96
+ yield* Effect.logDebug("[Scalus UPLC] Calling evalPlutusScripts...")
97
+ const redeemers = yield* Effect.try({
98
+ try: () => Scalus.Scalus.evalPlutusScripts(txBytes, utxosBytes, slotConfig, costModels),
99
+ catch: (error) => {
100
+ // Scalus error messages and evaluation logs, if any, are available to form an exception
101
+ const errorObj = error as any
102
+ const msg: string = errorObj?.message ?? "Unknown evaluation error"
103
+
104
+ return new TransactionBuilder.EvaluationError({
105
+ cause: error,
106
+ message: msg,
107
+ failures: []
108
+ })
109
+ }
110
+ })
111
+
112
+ yield* Effect.logDebug(`[Scalus UPLC] Evaluation successful - ${redeemers.length} redeemer(s) returned`)
113
+
114
+ // Check if redeemers array is empty
115
+ if (redeemers.length === 0) {
116
+ return yield* new TransactionBuilder.EvaluationError({
117
+ message: "Scalus evaluation returned no redeemers",
118
+ failures: []
119
+ })
120
+ }
121
+
122
+ // Transform Scalus redeemers to Evolution format and check for zero execution units
123
+ const evalRedeemers: Array<EvalRedeemer.EvalRedeemer> = []
124
+ for (const r of redeemers) {
125
+ const mem = BigInt(r.budget.memory)
126
+ const steps = BigInt(r.budget.steps)
127
+
128
+ // Check if execution units are zero (indicates evaluation failure)
129
+ if (mem === 0n && steps === 0n) {
130
+ return yield* Effect.fail(
131
+ new TransactionBuilder.EvaluationError({
132
+ message: `Scalus evaluation returned zero execution units for redeemer ${r.tag}:${r.index}`,
133
+ failures: []
134
+ })
135
+ )
136
+ }
137
+
138
+ const tagMap: Record<string, Redeemer.RedeemerTag> = {
139
+ Spend: "spend",
140
+ Mint: "mint",
141
+ Cert: "cert",
142
+ Reward: "reward",
143
+ Voting: "vote",
144
+ Proposing: "propose"
145
+ }
146
+
147
+ evalRedeemers.push({
148
+ redeemer_tag: tagMap[r.tag] || "spend",
149
+ redeemer_index: r.index,
150
+ ex_units: new Redeemer.ExUnits({ mem, steps })
151
+ })
152
+ }
153
+
154
+ return evalRedeemers
155
+ })
156
+ }
157
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Browser entry point - not implemented in rough draft
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+
7
+ import type * as TransactionBuilder from "@evolution-sdk/evolution/sdk/builders/TransactionBuilder"
8
+
9
+ /**
10
+ * Create a Scalus UPLC evaluator instance for browser environments.
11
+ *
12
+ * @throws Error - Browser support not yet implemented
13
+ */
14
+ export function createScalusEvaluator(): TransactionBuilder.Evaluator {
15
+ throw new Error("Browser support not yet implemented for Scalus UPLC evaluator")
16
+ }
@@ -0,0 +1,16 @@
1
+ import { makeEvaluator } from "./Evaluator.js"
2
+
3
+ /**
4
+ * Create a Scalus UPLC evaluator instance.
5
+ *
6
+ * @returns A TransactionBuilder.Evaluator that uses Scalus for script evaluation
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { createScalusEvaluator } from "@evolution-sdk/scalus-uplc"
11
+ *
12
+ * const evaluator = createScalusEvaluator()
13
+ * const redeemers = await Effect.runPromise(evaluator.evaluate(tx, utxos, context))
14
+ * ```
15
+ */
16
+ export const createScalusEvaluator = makeEvaluator()