@xo-cash/utils 0.0.2-development.15512051893 → 0.0.3-development.15744988955
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/index.d.mts +377 -19
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +439 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -10
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { binToHex, hexToBin, sha256, utf8ToBin } from "@bitauth/libauth";
|
|
2
|
-
import { BchVmVersions, XOTemplateLockingTypes, XOTemplateNftCapabilities, XOTemplatePrimitiveTypes } from "@xo-cash/types";
|
|
1
|
+
import { bigIntToVmNumber, binToHex, binToUtf8, createCompilerBch, hexToBin, sha256, utf8ToBin, vmNumberToBigInt } from "@bitauth/libauth";
|
|
2
|
+
import { BchVmVersions, XOTemplateBaseTypes, XOTemplateLockingTypes, XOTemplateNftCapabilities, XOTemplatePrimitiveTypes } from "@xo-cash/types";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { FungibleTokenAmount, NFTCommitment, PublicKey, Satoshis, SchnorrSignature, TemplateIdentifier, Timestamp, TokenCategory, TransactionHash } from "@xo-cash/primitives";
|
|
4
5
|
|
|
5
6
|
//#region source/extended-json.ts
|
|
6
7
|
/**
|
|
@@ -504,8 +505,13 @@ const xoTemplateNftCapabilitySchema = z.enum(XOTemplateNftCapabilities);
|
|
|
504
505
|
*/
|
|
505
506
|
const xoTemplateLockingTypeSchema = z.enum(XOTemplateLockingTypes);
|
|
506
507
|
/**
|
|
507
|
-
* Validation schema for a
|
|
508
|
-
*
|
|
508
|
+
* Validation schema for a base type identifier.
|
|
509
|
+
* Accepts values from XOTemplateBaseTypes for the `type` field on constants, variables, and data.
|
|
510
|
+
*/
|
|
511
|
+
const xoTemplateBaseTypeSchema = z.enum(XOTemplateBaseTypes);
|
|
512
|
+
/**
|
|
513
|
+
* Validation schema for a primitive type identifier.
|
|
514
|
+
* Accepts values from XOTemplatePrimitiveTypes for the `hint` field on constants, variables, and data.
|
|
509
515
|
*/
|
|
510
516
|
const xoTemplatePrimitiveTypeSchema = z.enum(XOTemplatePrimitiveTypes);
|
|
511
517
|
/**
|
|
@@ -976,9 +982,9 @@ const xoTemplateTransactionSchema = xoTemplateViewPropertiesSchema.extend({
|
|
|
976
982
|
* ```
|
|
977
983
|
*/
|
|
978
984
|
const xoTemplateConstantSchema = xoTemplateViewPropertiesSchema.extend({
|
|
979
|
-
type:
|
|
985
|
+
type: xoTemplateBaseTypeSchema.describe("The data type of this constant."),
|
|
980
986
|
value: z.unknown().describe("The value of this constant."),
|
|
981
|
-
hint:
|
|
987
|
+
hint: xoTemplatePrimitiveTypeSchema.optional().describe("An optional hint to help apps and users understand what this constant represents.")
|
|
982
988
|
}).strict();
|
|
983
989
|
/**
|
|
984
990
|
* Validation schema for a data field definition.
|
|
@@ -992,9 +998,9 @@ const xoTemplateConstantSchema = xoTemplateViewPropertiesSchema.extend({
|
|
|
992
998
|
* ```
|
|
993
999
|
*/
|
|
994
1000
|
const xoTemplateDataSchema = z.object({
|
|
995
|
-
type:
|
|
1001
|
+
type: xoTemplateBaseTypeSchema.describe("The data type of this data field."),
|
|
996
1002
|
value: z.unknown().describe("The value for this data field."),
|
|
997
|
-
hint:
|
|
1003
|
+
hint: xoTemplatePrimitiveTypeSchema.optional().describe("An optional hint to help apps and users understand this data field.")
|
|
998
1004
|
}).strict();
|
|
999
1005
|
/**
|
|
1000
1006
|
* Validation schema for an import default value intent. Extends the base intent with optional
|
|
@@ -1023,8 +1029,8 @@ const xoTemplateImportDefaultValueSchema = xoTemplateIntentSchema.extend(xoTempl
|
|
|
1023
1029
|
* ```
|
|
1024
1030
|
*/
|
|
1025
1031
|
const xoTemplateVariableSchema = xoTemplateViewPropertiesSchema.extend({
|
|
1026
|
-
type:
|
|
1027
|
-
hint:
|
|
1032
|
+
type: xoTemplateBaseTypeSchema.optional().describe("The data type of this variable."),
|
|
1033
|
+
hint: xoTemplatePrimitiveTypeSchema.optional().describe("A hint to help users understand what value to provide."),
|
|
1028
1034
|
importDefaultValue: xoTemplateImportDefaultValueSchema.optional().describe("A neutral intent that the engine uses to populate the default value for this variable.")
|
|
1029
1035
|
}).strict();
|
|
1030
1036
|
/**
|
|
@@ -1107,5 +1113,427 @@ const parseTemplate = (inputTemplate) => {
|
|
|
1107
1113
|
};
|
|
1108
1114
|
|
|
1109
1115
|
//#endregion
|
|
1110
|
-
|
|
1116
|
+
//#region source/cash-assembly/errors.ts
|
|
1117
|
+
/**
|
|
1118
|
+
* Error thrown when a required variable is missing.
|
|
1119
|
+
*/
|
|
1120
|
+
var CashAssemblyRequiredVariableMissingError = class extends Error {
|
|
1121
|
+
constructor(variableNames) {
|
|
1122
|
+
const defaultMessage = "Missing required variable";
|
|
1123
|
+
if (variableNames !== void 0 && variableNames.length > 0) super(`${defaultMessage}: variableNames [${variableNames.join(", ")}]`);
|
|
1124
|
+
else super(defaultMessage);
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
/**
|
|
1128
|
+
* Error thrown when cash assembly compilation fails.
|
|
1129
|
+
*/
|
|
1130
|
+
var CashAssemblyCompilationFailedError = class extends Error {
|
|
1131
|
+
constructor(message) {
|
|
1132
|
+
const defaultMessage = "Cash assembly compilation failed";
|
|
1133
|
+
super(message ? `${defaultMessage}: ${message}` : defaultMessage);
|
|
1134
|
+
}
|
|
1135
|
+
};
|
|
1136
|
+
/**
|
|
1137
|
+
* Error thrown when a variable's runtime type does not match the type required for compilation.
|
|
1138
|
+
*/
|
|
1139
|
+
var CashAssemblyVariableTypeMismatchError = class extends Error {
|
|
1140
|
+
constructor(variableKey, expectedType, actualType) {
|
|
1141
|
+
super(`Variable type mismatch: variableKey "${variableKey}", expected ${expectedType}, got ${actualType}`);
|
|
1142
|
+
}
|
|
1143
|
+
};
|
|
1144
|
+
/**
|
|
1145
|
+
* Error thrown when a supported primitive hint does not expose the requested method.
|
|
1146
|
+
*/
|
|
1147
|
+
var CashAssemblyPrimitiveMethodMissingError = class extends Error {
|
|
1148
|
+
constructor(identifier, methodName, hint) {
|
|
1149
|
+
super(`CashAssembly primitive method does not exist: identifier "${identifier}", methodName "${methodName}", hint "${hint}"`);
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
/**
|
|
1153
|
+
* Error thrown when a value cannot be resolved as bytes.
|
|
1154
|
+
*/
|
|
1155
|
+
var CashAssemblyUnsupportedValueTypeError = class extends Error {
|
|
1156
|
+
constructor(identifier, returnedType) {
|
|
1157
|
+
super(`CashAssembly value type is unsupported for byte resolution: identifier "${identifier}", returnedType "${returnedType}"`);
|
|
1158
|
+
}
|
|
1159
|
+
};
|
|
1160
|
+
/**
|
|
1161
|
+
* Error thrown when a number cannot be safely encoded as a CashAssembly VM number.
|
|
1162
|
+
*/
|
|
1163
|
+
var CashAssemblyNumberNotSafeIntegerError = class extends Error {
|
|
1164
|
+
constructor(identifier, value) {
|
|
1165
|
+
super(`CashAssembly number is not a safe integer: identifier "${identifier}", got ${String(value)}`);
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1168
|
+
/**
|
|
1169
|
+
* Error thrown when a supported primitive is selected but its value is missing when provided in the variables map.
|
|
1170
|
+
*/
|
|
1171
|
+
var CashAssemblyPrimitiveVariableMissingError = class extends Error {
|
|
1172
|
+
constructor(identifier, variableName) {
|
|
1173
|
+
super(`CashAssembly primitive variable is missing from the variables map: identifier "${identifier}", variableName "${variableName}"`);
|
|
1174
|
+
}
|
|
1175
|
+
};
|
|
1176
|
+
/**
|
|
1177
|
+
* Error thrown when compiled evaluation bytes cannot be decoded as a VM number.
|
|
1178
|
+
*/
|
|
1179
|
+
var CashAssemblyVmNumberDecodeError = class extends Error {
|
|
1180
|
+
constructor(reason) {
|
|
1181
|
+
super(`CashAssembly evaluation could not be decoded as a VM number: ${reason}`);
|
|
1182
|
+
}
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1185
|
+
//#endregion
|
|
1186
|
+
//#region source/cash-assembly/defaults.ts
|
|
1187
|
+
/**
|
|
1188
|
+
* Detects whether a string is a pure CashAssembly expression.
|
|
1189
|
+
*
|
|
1190
|
+
* CashAssembly expressions look like `$(<variable>)` or `$(<a> <b>)`. This pattern checks
|
|
1191
|
+
* that the entire string is one such expression and nothing else. It will not match if
|
|
1192
|
+
* there is other text surrounding the expression.
|
|
1193
|
+
*
|
|
1194
|
+
* For example:
|
|
1195
|
+
* `$(<fee>)` matches (a full expression)
|
|
1196
|
+
* `OP_DUP $(<fee>)` does not match (extra text before it)
|
|
1197
|
+
* `$()` does not match (empty expression)
|
|
1198
|
+
*/
|
|
1199
|
+
const CASHASSEMBLY_EXPRESSION_PATTERN = /^\$\([^)]+\)$/;
|
|
1200
|
+
/**
|
|
1201
|
+
* Finds all CashAssembly evaluations embedded in a larger string.
|
|
1202
|
+
*
|
|
1203
|
+
* An evaluation looks like `$(...)`, for example `$(<fee>)` or `$(<a> <b>)`. This pattern
|
|
1204
|
+
* locates every occurrence in the input and returns them all (global flag `g`).
|
|
1205
|
+
* Empty evaluations `$()` are intentionally excluded because they reference no variables.
|
|
1206
|
+
*
|
|
1207
|
+
* For example, scanning `"OP_DUP <$(<pubkeyHash>)> OP_HASH160 $(<fee>)"` would return
|
|
1208
|
+
* `['$(<pubkeyHash>)', '$(<fee>)']`.
|
|
1209
|
+
*/
|
|
1210
|
+
const CASHASSEMBLY_EVALUATION_PATTERN = /\$\([^)]+\)/g;
|
|
1211
|
+
/**
|
|
1212
|
+
* Extracts variable names from angle-bracket references inside a CashAssembly evaluation.
|
|
1213
|
+
*
|
|
1214
|
+
* Inside an evaluation like `$(<pubkeyHash> <fee>)`, variables are referenced as `<name>`.
|
|
1215
|
+
* This pattern captures the name between the brackets. The global flag `g` allows iterating
|
|
1216
|
+
* over every variable reference in a single evaluation string.
|
|
1217
|
+
*
|
|
1218
|
+
* For example, running this against `$(<pubkeyHash> <fee>)` would return the variable names
|
|
1219
|
+
* `["pubkeyHash", "fee"]`.
|
|
1220
|
+
*/
|
|
1221
|
+
const CASHASSEMBLY_VARIABLE_PATTERN = /<([^>]+)>/g;
|
|
1222
|
+
/**
|
|
1223
|
+
* Identifies CashAssembly literal tokens that appear inside angle-bracket push statements.
|
|
1224
|
+
*
|
|
1225
|
+
* Inside an evaluation, not everything between `<` and `>` is a variable name. Literals are
|
|
1226
|
+
* also valid push contents: numeric literals (e.g. `<0>`, `<32>`), hex literals (`<0x02>`),
|
|
1227
|
+
* binary literals (`<0b1010>`), and string literals (`<"minting">`, `<'hello'>`). This pattern
|
|
1228
|
+
* matches any captured token that starts with a digit or a quote character.
|
|
1229
|
+
*/
|
|
1230
|
+
const CASHASSEMBLY_LITERAL_TOKEN_PATTERN = /^[0-9"']/;
|
|
1231
|
+
/**
|
|
1232
|
+
* Matches a single dot variable method reference inside an angle-bracket identifier.
|
|
1233
|
+
*
|
|
1234
|
+
* Used to detect primitive method references such as `expiry.toIso8601`.
|
|
1235
|
+
*
|
|
1236
|
+
* For example:
|
|
1237
|
+
* `expiry.toIso8601` matches (base `expiry`, method `toIso8601`)
|
|
1238
|
+
* `requestedSatoshis` does not match (no method)
|
|
1239
|
+
* `key.schnorr_signature.all_outputs` does not match (more than one dot)
|
|
1240
|
+
* `key.public_key` matches the pattern shape but it is only resolved
|
|
1241
|
+
* when `hint` maps to a primitive
|
|
1242
|
+
*/
|
|
1243
|
+
const CASHASSEMBLY_VARIABLE_METHOD_REFERENCE_PATTERN = /^([^.]+)\.([^.]+)$/;
|
|
1244
|
+
|
|
1245
|
+
//#endregion
|
|
1246
|
+
//#region source/cash-assembly/bytes.ts
|
|
1247
|
+
/**
|
|
1248
|
+
* Converts a value into bytes representation.
|
|
1249
|
+
*
|
|
1250
|
+
* @param {unknown} value - Value to encode, should be one of: Uint8Array, bigint, boolean, string, or a safe integer number.
|
|
1251
|
+
* @param {string} valueIdentifier - Identifier used in error messages.
|
|
1252
|
+
* @returns {Uint8Array} Bytes representation of the value.
|
|
1253
|
+
* @throws {@link CashAssemblyNumberNotSafeIntegerError} When a number is not a safe integer.
|
|
1254
|
+
* @throws {@link CashAssemblyUnsupportedValueTypeError} When the value type cannot be resolved.
|
|
1255
|
+
*/
|
|
1256
|
+
const convertValueToBytes = (value, valueIdentifier) => {
|
|
1257
|
+
if (value instanceof Uint8Array) return value;
|
|
1258
|
+
if (typeof value === "bigint") return bigIntToVmNumber(value);
|
|
1259
|
+
if (typeof value === "boolean") return new Uint8Array(value ? [1] : []);
|
|
1260
|
+
if (typeof value === "string") return utf8ToBin(value);
|
|
1261
|
+
if (typeof value === "number") {
|
|
1262
|
+
if (Number.isSafeInteger(value) === true) return bigIntToVmNumber(BigInt(value));
|
|
1263
|
+
throw new CashAssemblyNumberNotSafeIntegerError(valueIdentifier, value);
|
|
1264
|
+
}
|
|
1265
|
+
throw new CashAssemblyUnsupportedValueTypeError(valueIdentifier, typeof value);
|
|
1266
|
+
};
|
|
1267
|
+
|
|
1268
|
+
//#endregion
|
|
1269
|
+
//#region source/cash-assembly/primitive-evaluations.ts
|
|
1270
|
+
/**
|
|
1271
|
+
* Template hint values mapped to a primitive class for resolving primitive method evaluations.
|
|
1272
|
+
* Keys are values from XOTemplatePrimitiveTypes.
|
|
1273
|
+
*/
|
|
1274
|
+
const PRIMITIVE_BY_TEMPLATE_HINT = {
|
|
1275
|
+
[XOTemplatePrimitiveTypes.FUNGIBLE_TOKEN_AMOUNT]: FungibleTokenAmount,
|
|
1276
|
+
[XOTemplatePrimitiveTypes.NFT_COMMITMENT]: NFTCommitment,
|
|
1277
|
+
[XOTemplatePrimitiveTypes.PUBLIC_KEY]: PublicKey,
|
|
1278
|
+
[XOTemplatePrimitiveTypes.SATOSHIS]: Satoshis,
|
|
1279
|
+
[XOTemplatePrimitiveTypes.SCHNORR_SIGNATURE]: SchnorrSignature,
|
|
1280
|
+
[XOTemplatePrimitiveTypes.TEMPLATE_IDENTIFIER]: TemplateIdentifier,
|
|
1281
|
+
[XOTemplatePrimitiveTypes.TIMESTAMP]: Timestamp,
|
|
1282
|
+
[XOTemplatePrimitiveTypes.TOKEN_CATEGORY]: TokenCategory,
|
|
1283
|
+
[XOTemplatePrimitiveTypes.TRANSACTION_HASH]: TransactionHash
|
|
1284
|
+
};
|
|
1285
|
+
/**
|
|
1286
|
+
* Returns true when `hint` maps to a supported primitive class in `PRIMITIVE_BY_TEMPLATE_HINT`.
|
|
1287
|
+
*
|
|
1288
|
+
* @param {XOTemplatePrimitiveType | undefined} hint - Template variable hint.
|
|
1289
|
+
* @returns {boolean} True when the hint selects a supported primitive class.
|
|
1290
|
+
*/
|
|
1291
|
+
const isSupportedPrimitiveHint = (hint) => {
|
|
1292
|
+
return hint !== void 0 && Object.hasOwn(PRIMITIVE_BY_TEMPLATE_HINT, hint) === true;
|
|
1293
|
+
};
|
|
1294
|
+
/**
|
|
1295
|
+
* Returns true when `methodName` is an own function on the primitive class for `hint`.
|
|
1296
|
+
*
|
|
1297
|
+
* @param {SupportedPrimitiveHint} hint - Supported template hint.
|
|
1298
|
+
* @param {string} methodName - Method name from the evaluation text, for example `toSatoshis`.
|
|
1299
|
+
* @returns {boolean} True when that class exposes the named method.
|
|
1300
|
+
*/
|
|
1301
|
+
const canResolvePrimitiveMethod = (hint, methodName) => {
|
|
1302
|
+
const PrimitiveClass = PRIMITIVE_BY_TEMPLATE_HINT[hint];
|
|
1303
|
+
if (Object.hasOwn(PrimitiveClass.prototype, methodName) === false) return false;
|
|
1304
|
+
return typeof Reflect.get(PrimitiveClass.prototype, methodName) === "function";
|
|
1305
|
+
};
|
|
1306
|
+
/**
|
|
1307
|
+
* Constructs a primitive from a raw value and calls one instance method on it.
|
|
1308
|
+
*
|
|
1309
|
+
* Call only after `canResolvePrimitiveMethod` is true for the same hint and method.
|
|
1310
|
+
*
|
|
1311
|
+
* @param {CallPrimitiveMethodParameters} parameters - Identifier, method, value, and supported hint.
|
|
1312
|
+
* @returns {unknown} Method return value, later encoded as CashAssembly push bytes.
|
|
1313
|
+
* @throws {@link CashAssemblyPrimitiveMethodMissingError} When the prototype member is not a function.
|
|
1314
|
+
* @throws When the primitive constructor rejects the raw value (validation errors from `@xo-cash/primitives`).
|
|
1315
|
+
*/
|
|
1316
|
+
const callPrimitiveMethod = (parameters) => {
|
|
1317
|
+
const { identifier, methodName, value, hint } = parameters;
|
|
1318
|
+
const PrimitiveClass = PRIMITIVE_BY_TEMPLATE_HINT[hint];
|
|
1319
|
+
const primitiveInstance = new PrimitiveClass(value);
|
|
1320
|
+
const primitiveMethod = Reflect.get(PrimitiveClass.prototype, methodName);
|
|
1321
|
+
if (typeof primitiveMethod !== "function") throw new CashAssemblyPrimitiveMethodMissingError(identifier, methodName, hint);
|
|
1322
|
+
return primitiveMethod.call(primitiveInstance);
|
|
1323
|
+
};
|
|
1324
|
+
/**
|
|
1325
|
+
* Resolves supported `base.method` identifiers to CashAssembly variable bytes.
|
|
1326
|
+
*
|
|
1327
|
+
* Each single dot identifier whose `hint` maps to a supported primitive is resolved and stored under
|
|
1328
|
+
* the full identifier (`base.method`). Unsupported or multi dot identifiers are left for CashAssembly.
|
|
1329
|
+
*
|
|
1330
|
+
* When `templateVariables` is omitted, returns an empty map.
|
|
1331
|
+
*
|
|
1332
|
+
* @param {ResolvePrimitiveMethodBytesParameters} parameters - Identifiers, values, and optional template metadata.
|
|
1333
|
+
* @returns {Record<string, Uint8Array>} Resolved method identifiers mapped to bytes for CashAssembly pushes.
|
|
1334
|
+
* @throws {@link CashAssemblyPrimitiveMethodMissingError} When the hint is a supported primitive but the method is missing.
|
|
1335
|
+
* @throws {@link CashAssemblyPrimitiveVariableMissingError} When the runtime value is missing from the variables map.
|
|
1336
|
+
* @throws {@link CashAssemblyUnsupportedValueTypeError} When the method return type cannot be embedded.
|
|
1337
|
+
* @throws {@link CashAssemblyNumberNotSafeIntegerError} When a method return value is a number that is not a safe integer.
|
|
1338
|
+
*/
|
|
1339
|
+
const resolvePrimitiveMethodBytes = (parameters) => {
|
|
1340
|
+
const { identifiers, templateVariables, variables } = parameters;
|
|
1341
|
+
if (templateVariables === void 0) return {};
|
|
1342
|
+
const resolvedBytes = {};
|
|
1343
|
+
for (const identifier of identifiers) {
|
|
1344
|
+
if (Object.hasOwn(resolvedBytes, identifier) === true) continue;
|
|
1345
|
+
const methodReferenceMatch = identifier.match(CASHASSEMBLY_VARIABLE_METHOD_REFERENCE_PATTERN);
|
|
1346
|
+
if (methodReferenceMatch === null) continue;
|
|
1347
|
+
const [, baseName, methodName] = methodReferenceMatch;
|
|
1348
|
+
if (Object.hasOwn(templateVariables, baseName) === false) continue;
|
|
1349
|
+
const hint = templateVariables[baseName].hint;
|
|
1350
|
+
if (isSupportedPrimitiveHint(hint) === false) continue;
|
|
1351
|
+
if (canResolvePrimitiveMethod(hint, methodName) === false) throw new CashAssemblyPrimitiveMethodMissingError(identifier, methodName, hint);
|
|
1352
|
+
if (Object.hasOwn(variables, baseName) === false) throw new CashAssemblyPrimitiveVariableMissingError(identifier, baseName);
|
|
1353
|
+
resolvedBytes[identifier] = convertValueToBytes(callPrimitiveMethod({
|
|
1354
|
+
identifier,
|
|
1355
|
+
methodName,
|
|
1356
|
+
value: variables[baseName],
|
|
1357
|
+
hint
|
|
1358
|
+
}), identifier);
|
|
1359
|
+
}
|
|
1360
|
+
return resolvedBytes;
|
|
1361
|
+
};
|
|
1362
|
+
|
|
1363
|
+
//#endregion
|
|
1364
|
+
//#region source/cash-assembly/evaluations.ts
|
|
1365
|
+
/**
|
|
1366
|
+
* Checks if the expression is a CashAssembly expression.
|
|
1367
|
+
*
|
|
1368
|
+
* @param {unknown} expression - The expression to check.
|
|
1369
|
+
* @returns {boolean} True if the expression is a CashAssembly expression, false otherwise.
|
|
1370
|
+
*/
|
|
1371
|
+
const isCashAssemblyExpression = (expression) => {
|
|
1372
|
+
return typeof expression === "string" && CASHASSEMBLY_EXPRESSION_PATTERN.test(expression);
|
|
1373
|
+
};
|
|
1374
|
+
/**
|
|
1375
|
+
* Extracts all CashAssembly evaluations (i.e., substrings like $(...)) from the input text.
|
|
1376
|
+
*
|
|
1377
|
+
* @param {string} text - The input string to scan for CashAssembly evaluations.
|
|
1378
|
+
* @returns {string[]} An array of evaluation strings found in the input.
|
|
1379
|
+
*
|
|
1380
|
+
* @example
|
|
1381
|
+
* extractCashAssemblyEvaluations("OP_DUP <$(<foo>)> OP_HASH160 $(<bar>)");
|
|
1382
|
+
* // returns ['$(<foo>)', '$(<bar>)']
|
|
1383
|
+
*/
|
|
1384
|
+
const extractCashAssemblyEvaluations = (text) => {
|
|
1385
|
+
return text.match(CASHASSEMBLY_EVALUATION_PATTERN) ?? [];
|
|
1386
|
+
};
|
|
1387
|
+
/**
|
|
1388
|
+
* Returns the segment of `identifier` before the first `.`.
|
|
1389
|
+
*
|
|
1390
|
+
* When there is no `.`, returns `identifier` unchanged.
|
|
1391
|
+
* Multi segment identifiers such as `foo.bar.baz` resolve to `foo`.
|
|
1392
|
+
*
|
|
1393
|
+
* @param {string} identifier - Identifier that may contain a dot.
|
|
1394
|
+
* @returns {string} The base name before the first `.`.
|
|
1395
|
+
*/
|
|
1396
|
+
const resolveIdentifierBaseName = (identifier) => {
|
|
1397
|
+
const firstDotIndex = identifier.indexOf(".");
|
|
1398
|
+
if (firstDotIndex === -1) return identifier;
|
|
1399
|
+
return identifier.slice(0, firstDotIndex);
|
|
1400
|
+
};
|
|
1401
|
+
/**
|
|
1402
|
+
* Extracts unique variable identifiers enclosed in angle brackets from each evaluation string.
|
|
1403
|
+
*
|
|
1404
|
+
* CashAssembly literal tokens such as hex bytes, numbers, and quoted strings are excluded via
|
|
1405
|
+
* {@link CASHASSEMBLY_LITERAL_TOKEN_PATTERN}. For example, `<0x02>` and `<"minting">` are not returned.
|
|
1406
|
+
*
|
|
1407
|
+
* @param {string[]} evaluations - An array of evaluation strings from which to extract variable names.
|
|
1408
|
+
* @returns {string[]} An array of variable names.
|
|
1409
|
+
*/
|
|
1410
|
+
const extractVariablesFromEvaluations = (evaluations) => {
|
|
1411
|
+
const uniqueVariables = /* @__PURE__ */ new Set();
|
|
1412
|
+
for (const evaluation of evaluations) for (const [, extractedIdentifier] of evaluation.matchAll(CASHASSEMBLY_VARIABLE_PATTERN)) {
|
|
1413
|
+
if (CASHASSEMBLY_LITERAL_TOKEN_PATTERN.test(extractedIdentifier)) continue;
|
|
1414
|
+
uniqueVariables.add(extractedIdentifier);
|
|
1415
|
+
}
|
|
1416
|
+
return [...uniqueVariables];
|
|
1417
|
+
};
|
|
1418
|
+
/**
|
|
1419
|
+
* Decodes compiled CashAssembly evaluation bytes into a string representation.
|
|
1420
|
+
*
|
|
1421
|
+
* 'evaluationDecodeMode' determines how the evaluation bytes are interpreted and presented.
|
|
1422
|
+
* Use `bigint` for numeric values like satoshis, `utf8` for text labels, `hex` for binary data
|
|
1423
|
+
* such as hashes, and `boolean` to represent boolean values.
|
|
1424
|
+
*
|
|
1425
|
+
* @param {Uint8Array} compiledResult - The compiled evaluation bytecode.
|
|
1426
|
+
* @param {CompiledCashAssemblyDecodeMode} [evaluationDecodeMode='utf8'] - The decode mode used to convert
|
|
1427
|
+
* bytes to text.
|
|
1428
|
+
* @returns {string} The decoded value as a string suitable for inline replacement.
|
|
1429
|
+
* @throws {@link CashAssemblyVmNumberDecodeError} When `evaluationDecodeMode` is `bigint` and the bytes are not a VM number.
|
|
1430
|
+
*/
|
|
1431
|
+
const decodeCompiledCashAssemblyEvaluation = (compiledResult, evaluationDecodeMode = "utf8") => {
|
|
1432
|
+
if (evaluationDecodeMode === "uint8array") return String(compiledResult);
|
|
1433
|
+
if (evaluationDecodeMode === "boolean") return compiledResult.length === 0 ? "false" : "true";
|
|
1434
|
+
if (evaluationDecodeMode === "hex") return binToHex(compiledResult);
|
|
1435
|
+
if (evaluationDecodeMode === "bigint") {
|
|
1436
|
+
const vmNumberResult = vmNumberToBigInt(compiledResult);
|
|
1437
|
+
if (typeof vmNumberResult === "bigint") return vmNumberResult.toString();
|
|
1438
|
+
throw new CashAssemblyVmNumberDecodeError(vmNumberResult);
|
|
1439
|
+
}
|
|
1440
|
+
return binToUtf8(compiledResult);
|
|
1441
|
+
};
|
|
1442
|
+
/**
|
|
1443
|
+
* Generates bytecode for a specific CashAssembly evaluation using given variable values and a prepared compiler.
|
|
1444
|
+
*
|
|
1445
|
+
* @param {CompilerBch} compiler - The libauth compiler from {@link compileCashAssemblyEvaluations}.
|
|
1446
|
+
* @param {string} evaluation - The specific evaluation string to compile.
|
|
1447
|
+
* @param {Record<string, Uint8Array>} variables - A record mapping variable names to their values.
|
|
1448
|
+
* @returns {Uint8Array} The compiled bytecode.
|
|
1449
|
+
* @throws {@link CashAssemblyRequiredVariableMissingError} If a required variable is not present.
|
|
1450
|
+
* @throws {@link CashAssemblyVariableTypeMismatchError} If a variable value is not a Uint8Array.
|
|
1451
|
+
* @throws {@link CashAssemblyCompilationFailedError} If libauth compilation fails.
|
|
1452
|
+
*/
|
|
1453
|
+
const generateCashAssemblyBytecode = (compiler, evaluation, variables) => {
|
|
1454
|
+
const variableNames = extractVariablesFromEvaluations([evaluation]);
|
|
1455
|
+
const missingVariables = variableNames.filter((name) => !Object.hasOwn(variables, name));
|
|
1456
|
+
if (missingVariables.length > 0) throw new CashAssemblyRequiredVariableMissingError(missingVariables);
|
|
1457
|
+
const bytecode = {};
|
|
1458
|
+
for (const variableName of variableNames) {
|
|
1459
|
+
const value = variables[variableName];
|
|
1460
|
+
if (!(value instanceof Uint8Array)) throw new CashAssemblyVariableTypeMismatchError(variableName, "Uint8Array", typeof value);
|
|
1461
|
+
bytecode[variableName] = value;
|
|
1462
|
+
}
|
|
1463
|
+
const compiledBytecode = compiler.generateBytecode({
|
|
1464
|
+
data: { bytecode },
|
|
1465
|
+
scriptId: evaluation
|
|
1466
|
+
});
|
|
1467
|
+
if (!compiledBytecode.success) {
|
|
1468
|
+
let compilationFailureMessage = "unknown compilation failure";
|
|
1469
|
+
if ("errors" in compiledBytecode && compiledBytecode.errors.length > 0) compilationFailureMessage = compiledBytecode.errors.map((compilationError) => compilationError.error).join("; ");
|
|
1470
|
+
throw new CashAssemblyCompilationFailedError(compilationFailureMessage);
|
|
1471
|
+
}
|
|
1472
|
+
return compiledBytecode.bytecode;
|
|
1473
|
+
};
|
|
1474
|
+
/**
|
|
1475
|
+
* Prepares a compiler for the provided CashAssembly evaluations, setting required variables as 'WalletData'.
|
|
1476
|
+
*
|
|
1477
|
+
* @param {string[]} evaluations - Array of evaluation strings (e.g., ['$(<var1>)', '$(<var2> <var3>)']).
|
|
1478
|
+
* @returns {CompilerBch} A Libauth compiler instance for use with these evaluations.
|
|
1479
|
+
*/
|
|
1480
|
+
const compileCashAssemblyEvaluations = (evaluations) => {
|
|
1481
|
+
const scripts = {};
|
|
1482
|
+
for (const evaluation of evaluations) scripts[evaluation] = evaluation;
|
|
1483
|
+
const variableNames = extractVariablesFromEvaluations(evaluations);
|
|
1484
|
+
const variables = {};
|
|
1485
|
+
for (const variableName of variableNames) variables[resolveIdentifierBaseName(variableName)] = { type: "WalletData" };
|
|
1486
|
+
return createCompilerBch({
|
|
1487
|
+
scripts,
|
|
1488
|
+
variables
|
|
1489
|
+
});
|
|
1490
|
+
};
|
|
1491
|
+
/**
|
|
1492
|
+
* Compiles all CashAssembly evaluations in a text string and replaces each evaluation
|
|
1493
|
+
* with a decoded string representation.
|
|
1494
|
+
*
|
|
1495
|
+
* @param {CompileCashAssemblyStringParameters} parameters - Parameters for compiling the CashAssembly string.
|
|
1496
|
+
* @param {string} parameters.cashAssemblyText - The string with CashAssembly evaluations.
|
|
1497
|
+
* @param {Record<string, XOInvitationVariableValue | Uint8Array>} parameters.variables - Object mapping
|
|
1498
|
+
* variable names to values for compilation.
|
|
1499
|
+
* @param {CompiledCashAssemblyDecodeMode} [parameters.evaluationDecodeMode='utf8'] - The decode mode used
|
|
1500
|
+
* after each evaluation is compiled. See {@link decodeCompiledCashAssemblyEvaluation}.
|
|
1501
|
+
* @param {XOTemplate['variables']} [parameters.templateVariables] - Optional template variable definitions
|
|
1502
|
+
* used to resolve supported `<name.method>` pushes via each variable's `hint`.
|
|
1503
|
+
* @returns {string} Compiled text with all evaluations replaced by decoded string values.
|
|
1504
|
+
* @throws {@link CashAssemblyRequiredVariableMissingError} When a required variable is not present in the variables map.
|
|
1505
|
+
* @throws {@link CashAssemblyPrimitiveMethodMissingError} When a supported primitive hint has an unknown method.
|
|
1506
|
+
* @throws {@link CashAssemblyPrimitiveVariableMissingError} When a supported primitive method is missing its runtime value.
|
|
1507
|
+
* @throws {@link CashAssemblyUnsupportedValueTypeError} When a primitive method return type cannot be embedded as bytes.
|
|
1508
|
+
* @throws {@link CashAssemblyNumberNotSafeIntegerError} When a number variable is not a safe integer.
|
|
1509
|
+
* @throws {@link CashAssemblyVmNumberDecodeError} When `evaluationDecodeMode` is `bigint` and an evaluation is not a VM number.
|
|
1510
|
+
*/
|
|
1511
|
+
const compileCashAssemblyString = (parameters) => {
|
|
1512
|
+
const { cashAssemblyText, variables, evaluationDecodeMode = "utf8", templateVariables } = parameters;
|
|
1513
|
+
return cashAssemblyText.replace(CASHASSEMBLY_EVALUATION_PATTERN, (evaluation) => {
|
|
1514
|
+
const variableNames = extractVariablesFromEvaluations([evaluation]);
|
|
1515
|
+
const primitiveMethodBytes = resolvePrimitiveMethodBytes({
|
|
1516
|
+
identifiers: variableNames,
|
|
1517
|
+
templateVariables,
|
|
1518
|
+
variables
|
|
1519
|
+
});
|
|
1520
|
+
const missingVariables = variableNames.filter((variableName) => {
|
|
1521
|
+
if (Object.hasOwn(primitiveMethodBytes, variableName) === true) return false;
|
|
1522
|
+
return Object.hasOwn(variables, variableName) === false;
|
|
1523
|
+
});
|
|
1524
|
+
if (missingVariables.length > 0) throw new CashAssemblyRequiredVariableMissingError(missingVariables);
|
|
1525
|
+
const variableBytes = {};
|
|
1526
|
+
for (const variableName of variableNames) {
|
|
1527
|
+
if (Object.hasOwn(primitiveMethodBytes, variableName) === true) {
|
|
1528
|
+
variableBytes[variableName] = primitiveMethodBytes[variableName];
|
|
1529
|
+
continue;
|
|
1530
|
+
}
|
|
1531
|
+
variableBytes[variableName] = convertValueToBytes(variables[variableName], variableName);
|
|
1532
|
+
}
|
|
1533
|
+
return decodeCompiledCashAssemblyEvaluation(generateCashAssemblyBytecode(compileCashAssemblyEvaluations([evaluation]), evaluation, variableBytes), evaluationDecodeMode);
|
|
1534
|
+
});
|
|
1535
|
+
};
|
|
1536
|
+
|
|
1537
|
+
//#endregion
|
|
1538
|
+
export { AsyncPushIterator, CASHASSEMBLY_EVALUATION_PATTERN, CASHASSEMBLY_EXPRESSION_PATTERN, CASHASSEMBLY_LITERAL_TOKEN_PATTERN, CASHASSEMBLY_VARIABLE_METHOD_REFERENCE_PATTERN, CASHASSEMBLY_VARIABLE_PATTERN, CashAssemblyCompilationFailedError, CashAssemblyNumberNotSafeIntegerError, CashAssemblyPrimitiveMethodMissingError, CashAssemblyPrimitiveVariableMissingError, CashAssemblyRequiredVariableMissingError, CashAssemblyUnsupportedValueTypeError, CashAssemblyVariableTypeMismatchError, CashAssemblyVmNumberDecodeError, SSEEventParser, TemplateInvalidError, TemplateJsonMalformedError, TemplateSerializationFailedError, VIEW_PROPERTIES_DESCRIPTION_MAX_LENGTH, VIEW_PROPERTIES_ICON_MAX_LENGTH, VIEW_PROPERTIES_NAME_MAX_LENGTH, bchVmVersionSchema, buildErrorDescription, compileCashAssemblyEvaluations, compileCashAssemblyString, convertValueToBytes, decodeCompiledCashAssemblyEvaluation, extendedJsonReplacer, extendedJsonReviver, extractCashAssemblyEvaluations, extractVariablesFromEvaluations, fromExtendedJson, generateCashAssemblyBytecode, generateTemplateIdentifier, isCashAssemblyExpression, parseTemplate, resolvePrimitiveMethodBytes, satoshisSchema, scriptToScriptHash, serializeTemplate, toExtendedJson, uint8ArraySchema, xoTemplateActionIntentSchema, xoTemplateActionRequirementsSchema, xoTemplateActionRoleRequirementsSchema, xoTemplateActionRoleSchema, xoTemplateActionSchema, xoTemplateAssetAmountsSchema, xoTemplateBaseTypeSchema, xoTemplateConstantSchema, xoTemplateDataSchema, xoTemplateDefaultsSchema, xoTemplateIconSchema, xoTemplateImportDefaultValueSchema, xoTemplateInputSchema, xoTemplateIntentSchema, xoTemplateLockingScriptIntentSchema, xoTemplateLockingScriptRoleSchema, xoTemplateLockingScriptSchema, xoTemplateLockingTypeSchema, xoTemplateNftCapabilitySchema, xoTemplateNonFungibleTokenDetailsSchema, xoTemplateOutputIntentSchema, xoTemplateOutputSchema, xoTemplatePrimitiveTypeSchema, xoTemplateResourceSchema, xoTemplateRoleSlotSchema, xoTemplateRoleSlotsRequirementsSchema, xoTemplateSchema, xoTemplateStateSchema, xoTemplateTokenSchema, xoTemplateTransactionInputSchema, xoTemplateTransactionOutputSchema, xoTemplateTransactionRoleDataSchema, xoTemplateTransactionSchema, xoTemplateVariableSchema, xoTemplateViewPropertiesSchema };
|
|
1111
1539
|
//# sourceMappingURL=index.mjs.map
|