@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.
- package/dist/Evaluator.d.ts +3 -0
- package/dist/Evaluator.d.ts.map +1 -0
- package/dist/Evaluator.js +118 -0
- package/dist/Evaluator.js.map +1 -0
- package/dist/index.browser.d.ts +13 -0
- package/dist/index.browser.d.ts.map +1 -0
- package/dist/index.browser.js +14 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.node.d.ts +15 -0
- package/dist/index.node.d.ts.map +1 -0
- package/dist/index.node.js +16 -0
- package/dist/index.node.js.map +1 -0
- package/package.json +84 -0
- package/src/Evaluator.ts +157 -0
- package/src/index.browser.ts +16 -0
- package/src/index.node.ts +16 -0
|
@@ -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
|
+
}
|
package/src/Evaluator.ts
ADDED
|
@@ -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()
|