@callcium/sdk 0.11.1 → 0.12.0
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.ts +101 -88
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +104 -72
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/bytes.ts +8 -25
- package/src/calldata-reader.ts +3 -3
- package/src/constants.ts +5 -1
- package/src/constraint.ts +40 -22
- package/src/descriptor-coder.ts +14 -23
- package/src/descriptor.ts +18 -19
- package/src/errors.ts +14 -17
- package/src/index.ts +2 -3
- package/src/operators.ts +65 -35
- package/src/path.ts +1 -2
- package/src/policy-builder.ts +15 -20
- package/src/policy-coder.ts +20 -29
- package/src/policy-enforcer.ts +21 -23
- package/src/policy-validator.ts +51 -44
- package/src/signature.ts +6 -6
- package/src/type-desc.ts +6 -6
- package/src/types.ts +11 -16
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { bytesToHex as bytesToHex$1, concatBytes, hexToBytes as hexToBytes$1, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
1
2
|
import { keccak_256 } from "@noble/hashes/sha3.js";
|
|
2
|
-
import { utf8ToBytes } from "@noble/hashes/utils.js";
|
|
3
3
|
//#region src/errors.ts
|
|
4
4
|
var CallciumError = class extends Error {
|
|
5
5
|
code;
|
|
@@ -36,29 +36,17 @@ function formatDiagnostic(violation) {
|
|
|
36
36
|
//#endregion
|
|
37
37
|
//#region src/bytes.ts
|
|
38
38
|
const hexBodyPattern = /^[0-9a-fA-F]*$/;
|
|
39
|
-
const HEX_DIGITS = "0123456789abcdef";
|
|
40
|
-
const nibble = new Int8Array(128).fill(-1);
|
|
41
|
-
for (let value = 0; value < 16; value++) {
|
|
42
|
-
nibble[HEX_DIGITS.charCodeAt(value)] = value;
|
|
43
|
-
nibble[HEX_DIGITS.toUpperCase().charCodeAt(value)] = value;
|
|
44
|
-
}
|
|
45
39
|
function hexToBytes(hex) {
|
|
46
40
|
const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
47
41
|
if (clean.length % 2 !== 0) throw new CallciumError("INVALID_HEX", "Odd-length hex string");
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (high < 0 || low < 0) throw new CallciumError("INVALID_HEX", "Invalid hex characters");
|
|
53
|
-
bytes[i] = high << 4 | low;
|
|
42
|
+
try {
|
|
43
|
+
return hexToBytes$1(clean);
|
|
44
|
+
} catch {
|
|
45
|
+
throw new CallciumError("INVALID_HEX", "Invalid hex characters");
|
|
54
46
|
}
|
|
55
|
-
return bytes;
|
|
56
47
|
}
|
|
57
|
-
const hexPairs = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
58
48
|
function bytesToHex(bytes) {
|
|
59
|
-
|
|
60
|
-
for (let i = 0; i < bytes.length; i++) body += hexPairs[bytes[i]];
|
|
61
|
-
return `0x${body}`;
|
|
49
|
+
return `0x${bytesToHex$1(bytes)}`;
|
|
62
50
|
}
|
|
63
51
|
function toHex(data, start, end) {
|
|
64
52
|
return bytesToHex(data.subarray(start, end));
|
|
@@ -335,6 +323,30 @@ const OP_TABLE = [
|
|
|
335
323
|
label: "== ctx",
|
|
336
324
|
operands: "single"
|
|
337
325
|
},
|
|
326
|
+
{
|
|
327
|
+
key: "GT_CTX",
|
|
328
|
+
code: 9,
|
|
329
|
+
label: "> ctx",
|
|
330
|
+
operands: "single"
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
key: "LT_CTX",
|
|
334
|
+
code: 10,
|
|
335
|
+
label: "< ctx",
|
|
336
|
+
operands: "single"
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
key: "GTE_CTX",
|
|
340
|
+
code: 11,
|
|
341
|
+
label: ">= ctx",
|
|
342
|
+
operands: "single"
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
key: "LTE_CTX",
|
|
346
|
+
code: 12,
|
|
347
|
+
label: "<= ctx",
|
|
348
|
+
operands: "single"
|
|
349
|
+
},
|
|
338
350
|
{
|
|
339
351
|
key: "BITMASK_ALL",
|
|
340
352
|
code: 16,
|
|
@@ -544,6 +556,18 @@ var ConstraintBuilder = class {
|
|
|
544
556
|
neqCtx(contextPropertyId) {
|
|
545
557
|
return this.push(singleOp(Op.EQ_CTX | Op.NOT, contextOperand(contextPropertyId)));
|
|
546
558
|
}
|
|
559
|
+
gtCtx(contextPropertyId) {
|
|
560
|
+
return this.push(singleOp(Op.GT_CTX, contextOperand(contextPropertyId)));
|
|
561
|
+
}
|
|
562
|
+
ltCtx(contextPropertyId) {
|
|
563
|
+
return this.push(singleOp(Op.LT_CTX, contextOperand(contextPropertyId)));
|
|
564
|
+
}
|
|
565
|
+
gteCtx(contextPropertyId) {
|
|
566
|
+
return this.push(singleOp(Op.GTE_CTX, contextOperand(contextPropertyId)));
|
|
567
|
+
}
|
|
568
|
+
lteCtx(contextPropertyId) {
|
|
569
|
+
return this.push(singleOp(Op.LTE_CTX, contextOperand(contextPropertyId)));
|
|
570
|
+
}
|
|
547
571
|
gt(bound) {
|
|
548
572
|
return this.push(singleOp(Op.GT, bound), [bound]);
|
|
549
573
|
}
|
|
@@ -656,13 +680,9 @@ function isLengthOp(opCode) {
|
|
|
656
680
|
const base = opCode & ~Op.NOT;
|
|
657
681
|
return base >= Op.LENGTH_EQ && base <= Op.LENGTH_BETWEEN;
|
|
658
682
|
}
|
|
659
|
-
function
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
if (base === Op.LENGTH_LT) return Op.LT;
|
|
663
|
-
if (base === Op.LENGTH_GTE) return Op.GTE;
|
|
664
|
-
if (base === Op.LENGTH_LTE) return Op.LTE;
|
|
665
|
-
return Op.BETWEEN;
|
|
683
|
+
function isContextOp(opCode) {
|
|
684
|
+
const base = opCode & ~Op.NOT;
|
|
685
|
+
return base >= Op.EQ_CTX && base <= Op.LTE_CTX;
|
|
666
686
|
}
|
|
667
687
|
function isLengthValidType(typeCode) {
|
|
668
688
|
return typeCode === TypeCode.BYTES || typeCode === TypeCode.STRING || typeCode === TypeCode.DYNAMIC_ARRAY;
|
|
@@ -689,12 +709,7 @@ function isIn(value, data) {
|
|
|
689
709
|
return false;
|
|
690
710
|
}
|
|
691
711
|
function applyOperator(opCode, value, valueLength, operandData, typeCode) {
|
|
692
|
-
|
|
693
|
-
if (isLengthOp(base)) {
|
|
694
|
-
value = valueLength;
|
|
695
|
-
typeCode = TypeCode.UINT_MAX;
|
|
696
|
-
base = lengthToValueOp(base);
|
|
697
|
-
}
|
|
712
|
+
const base = opCode & ~Op.NOT;
|
|
698
713
|
let result;
|
|
699
714
|
switch (base) {
|
|
700
715
|
case Op.EQ:
|
|
@@ -726,16 +741,48 @@ function applyOperator(opCode, value, valueLength, operandData, typeCode) {
|
|
|
726
741
|
result = (value & mask) === mask;
|
|
727
742
|
break;
|
|
728
743
|
}
|
|
729
|
-
case Op.BITMASK_ANY:
|
|
730
|
-
|
|
731
|
-
result = (value & mask) !== 0n;
|
|
744
|
+
case Op.BITMASK_ANY:
|
|
745
|
+
result = (value & toBigInt(operandData, 0)) !== 0n;
|
|
732
746
|
break;
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
747
|
+
case Op.BITMASK_NONE:
|
|
748
|
+
result = (value & toBigInt(operandData, 0)) === 0n;
|
|
749
|
+
break;
|
|
750
|
+
case Op.LENGTH_EQ:
|
|
751
|
+
result = valueLength === toBigInt(operandData, 0);
|
|
752
|
+
break;
|
|
753
|
+
case Op.LENGTH_GT:
|
|
754
|
+
result = valueLength > toBigInt(operandData, 0);
|
|
755
|
+
break;
|
|
756
|
+
case Op.LENGTH_LT:
|
|
757
|
+
result = valueLength < toBigInt(operandData, 0);
|
|
758
|
+
break;
|
|
759
|
+
case Op.LENGTH_GTE:
|
|
760
|
+
result = valueLength >= toBigInt(operandData, 0);
|
|
761
|
+
break;
|
|
762
|
+
case Op.LENGTH_LTE:
|
|
763
|
+
result = valueLength <= toBigInt(operandData, 0);
|
|
764
|
+
break;
|
|
765
|
+
case Op.LENGTH_BETWEEN: {
|
|
766
|
+
const lower = toBigInt(operandData, 0);
|
|
767
|
+
const upper = toBigInt(operandData, 32);
|
|
768
|
+
result = valueLength >= lower && valueLength <= upper;
|
|
737
769
|
break;
|
|
738
770
|
}
|
|
771
|
+
case Op.EQ_CTX:
|
|
772
|
+
result = value === toBigInt(operandData, 0);
|
|
773
|
+
break;
|
|
774
|
+
case Op.GT_CTX:
|
|
775
|
+
result = value > toBigInt(operandData, 0);
|
|
776
|
+
break;
|
|
777
|
+
case Op.LT_CTX:
|
|
778
|
+
result = value < toBigInt(operandData, 0);
|
|
779
|
+
break;
|
|
780
|
+
case Op.GTE_CTX:
|
|
781
|
+
result = value >= toBigInt(operandData, 0);
|
|
782
|
+
break;
|
|
783
|
+
case Op.LTE_CTX:
|
|
784
|
+
result = value <= toBigInt(operandData, 0);
|
|
785
|
+
break;
|
|
739
786
|
default: throw new CallciumError("UNKNOWN_OPERATOR", `Unknown operator code ${formatCode(base, PolicyFormat.RULE_OPCODE_SIZE)}`);
|
|
740
787
|
}
|
|
741
788
|
return (opCode & Op.NOT) !== 0 ? !result : result;
|
|
@@ -1238,15 +1285,7 @@ function fromTypes(typesCsv) {
|
|
|
1238
1285
|
segments.push([segStart, typesCsv.length]);
|
|
1239
1286
|
const paramDescs = segments.map(([start, end]) => parseType(typesCsv, start, end));
|
|
1240
1287
|
if (paramDescs.length > DescriptorFormat.MAX_PARAMS) throw new CallciumError("TOO_MANY_PARAMS", `Parameter count ${paramDescs.length} exceeds maximum ${DescriptorFormat.MAX_PARAMS}`);
|
|
1241
|
-
const
|
|
1242
|
-
const result = new Uint8Array(DescriptorFormat.HEADER_SIZE + totalBytes);
|
|
1243
|
-
result[0] = DescriptorFormat.VERSION;
|
|
1244
|
-
result[1] = paramDescs.length;
|
|
1245
|
-
let offset = DescriptorFormat.HEADER_SIZE;
|
|
1246
|
-
for (const desc of paramDescs) {
|
|
1247
|
-
result.set(desc, offset);
|
|
1248
|
-
offset += desc.length;
|
|
1249
|
-
}
|
|
1288
|
+
const result = concatBytes(Uint8Array.of(DescriptorFormat.VERSION, paramDescs.length), ...paramDescs);
|
|
1250
1289
|
decodeDescriptor(result);
|
|
1251
1290
|
return result;
|
|
1252
1291
|
}
|
|
@@ -1532,8 +1571,8 @@ function decodePolicy(blob) {
|
|
|
1532
1571
|
prev = cur;
|
|
1533
1572
|
}
|
|
1534
1573
|
}
|
|
1535
|
-
if (opBase
|
|
1536
|
-
if (toBigInt(data, dataStart) > BigInt(MAX_CONTEXT_PROPERTY_ID)) throw new CallciumError("UNKNOWN_CONTEXT_PROPERTY", "
|
|
1574
|
+
if (isContextOp(opBase)) {
|
|
1575
|
+
if (toBigInt(data, dataStart) > BigInt(MAX_CONTEXT_PROPERTY_ID)) throw new CallciumError("UNKNOWN_CONTEXT_PROPERTY", "Context reference operand references an undefined context property", ruleOffset);
|
|
1537
1576
|
}
|
|
1538
1577
|
if (depthValue === 0) throw new CallciumError("EMPTY_PATH", "Rule path must have at least one step", ruleOffset);
|
|
1539
1578
|
if (depthValue > PolicyFormat.MAX_PATH_DEPTH) throw new CallciumError("PATH_TOO_DEEP", `Path depth ${depthValue} exceeds maximum ${PolicyFormat.MAX_PATH_DEPTH}`, ruleOffset);
|
|
@@ -1669,15 +1708,7 @@ function encodeRule(rule) {
|
|
|
1669
1708
|
return buf;
|
|
1670
1709
|
}
|
|
1671
1710
|
function encodeGroupRules(rules) {
|
|
1672
|
-
|
|
1673
|
-
const totalSize = parts.reduce((sum, p) => sum + p.length, 0);
|
|
1674
|
-
const buf = new Uint8Array(totalSize);
|
|
1675
|
-
let offset = 0;
|
|
1676
|
-
for (const part of parts) {
|
|
1677
|
-
buf.set(part, offset);
|
|
1678
|
-
offset += part.length;
|
|
1679
|
-
}
|
|
1680
|
-
return buf;
|
|
1711
|
+
return concatBytes(...rules.map(encodeRule));
|
|
1681
1712
|
}
|
|
1682
1713
|
function buildOperatorHex(rule) {
|
|
1683
1714
|
return `0x${rule.opCode.value.toString(16).padStart(2, "0")}${rule.data.value.slice(2)}`;
|
|
@@ -2259,7 +2290,7 @@ function isComparisonOp(opBase) {
|
|
|
2259
2290
|
function isBitmaskOp(opBase) {
|
|
2260
2291
|
return opBase >= Op.BITMASK_ALL && opBase <= Op.BITMASK_NONE;
|
|
2261
2292
|
}
|
|
2262
|
-
function
|
|
2293
|
+
function checkCompatibility(opBase, typeInfo) {
|
|
2263
2294
|
const { typeCode, isDynamic, staticSize } = typeInfo;
|
|
2264
2295
|
if (isValueOp(opBase)) {
|
|
2265
2296
|
if (isDynamic || staticSize !== 32) return {
|
|
@@ -2282,7 +2313,7 @@ function getIncompat(opBase, typeInfo) {
|
|
|
2282
2313
|
code: "IN_ON_BOOL",
|
|
2283
2314
|
message: "IN operator used on boolean type"
|
|
2284
2315
|
};
|
|
2285
|
-
if (opBase
|
|
2316
|
+
if (isContextOp(opBase) && !(typeCode >= TypeCode.UINT_MIN && typeCode <= TypeCode.UINT_MAX) && !(opBase === Op.EQ_CTX && typeCode === TypeCode.ADDRESS)) return {
|
|
2286
2317
|
code: "CONTEXT_TYPE_MISMATCH",
|
|
2287
2318
|
message: "Context reference operator used on incompatible type"
|
|
2288
2319
|
};
|
|
@@ -2301,7 +2332,8 @@ function getIncompat(opBase, typeInfo) {
|
|
|
2301
2332
|
};
|
|
2302
2333
|
}
|
|
2303
2334
|
function isOpAllowed(opCode, typeInfo) {
|
|
2304
|
-
|
|
2335
|
+
const opBase = opCode & ~Op.NOT;
|
|
2336
|
+
return operandsOf(opBase) !== void 0 && checkCompatibility(opBase, typeInfo) === null;
|
|
2305
2337
|
}
|
|
2306
2338
|
function readValue(opHex) {
|
|
2307
2339
|
return BigInt(`0x${opHex.slice(4)}`);
|
|
@@ -2571,9 +2603,9 @@ function checkDuplicates(issues, operators, groupIndex, constraintIndex) {
|
|
|
2571
2603
|
}
|
|
2572
2604
|
function checkFusibleRange(ctx, operators, groupIndex, constraintIndex, issues) {
|
|
2573
2605
|
const numericPair = findLonePair(operators, Op.GTE, Op.LTE);
|
|
2574
|
-
if (numericPair &&
|
|
2606
|
+
if (numericPair && checkCompatibility(Op.GTE, ctx.typeInfo) === null && signedCompare(numericPair.low, numericPair.high, ctx.numeric.isSigned) <= 0n) issues.push(fusibleRange(false, groupIndex, constraintIndex, bigintToHex(numericPair.low), bigintToHex(numericPair.high)));
|
|
2575
2607
|
const lengthPair = findLonePair(operators, Op.LENGTH_GTE, Op.LENGTH_LTE);
|
|
2576
|
-
if (lengthPair &&
|
|
2608
|
+
if (lengthPair && checkCompatibility(Op.LENGTH_GTE, ctx.typeInfo) === null && lengthPair.low <= lengthPair.high) issues.push(fusibleRange(true, groupIndex, constraintIndex, bigintToHex(lengthPair.low), bigintToHex(lengthPair.high)));
|
|
2577
2609
|
}
|
|
2578
2610
|
function hasValidPayload(opBase, dataLength) {
|
|
2579
2611
|
return dataLength <= fieldMax(PolicyFormat.RULE_DATALENGTH_SIZE) && isValidOperatorData(opBase, dataLength);
|
|
@@ -2613,12 +2645,12 @@ function validateConstraint(ctx, constraint, groupIndex, constraintIndex, issues
|
|
|
2613
2645
|
}
|
|
2614
2646
|
const isNegated = (opCode & Op.NOT) !== 0;
|
|
2615
2647
|
if (underAny && isNegated) issues.push(negationUnderAny(groupIndex, constraintIndex, bigintToHex(BigInt(opCode))));
|
|
2616
|
-
const
|
|
2617
|
-
if (
|
|
2618
|
-
issues.push(fromOpRule(
|
|
2648
|
+
const incompatibility = checkCompatibility(base, ctx.typeInfo);
|
|
2649
|
+
if (incompatibility) {
|
|
2650
|
+
issues.push(fromOpRule(incompatibility.code, incompatibility.message, groupIndex, constraintIndex, bigintToHex(BigInt(opCode))));
|
|
2619
2651
|
continue;
|
|
2620
2652
|
}
|
|
2621
|
-
if (base
|
|
2653
|
+
if (isContextOp(base)) {
|
|
2622
2654
|
const ctxOperand = readValue(opHex);
|
|
2623
2655
|
const property = findContextProperty(Number(ctxOperand));
|
|
2624
2656
|
if (!property) issues.push(unknownContextProperty(groupIndex, constraintIndex, bigintToHex(ctxOperand), bigintToHex(BigInt(MAX_CONTEXT_PROPERTY_ID))));
|
|
@@ -3002,7 +3034,7 @@ function resolveContextOperand(operandData, context) {
|
|
|
3002
3034
|
return contextValueToWord(value);
|
|
3003
3035
|
}
|
|
3004
3036
|
function referenceOperand(opCode, operandData, context) {
|
|
3005
|
-
if ((opCode
|
|
3037
|
+
if (!isContextOp(opCode)) return void 0;
|
|
3006
3038
|
return resolveContextOperand(operandData, context);
|
|
3007
3039
|
}
|
|
3008
3040
|
function readTargetBlock(hint, targetOffset) {
|
|
@@ -3071,7 +3103,7 @@ function evalTarget(callData, target, block, opCode, operandData, ctxOperand) {
|
|
|
3071
3103
|
ctxTypeCode: ctxOperand.ctxTypeCode
|
|
3072
3104
|
};
|
|
3073
3105
|
return {
|
|
3074
|
-
passed: value
|
|
3106
|
+
passed: applyOperator(opCode, value, 32n, hexToBytes(bigintToHex(ctxOperand)), typeCode),
|
|
3075
3107
|
value,
|
|
3076
3108
|
ctxOperand
|
|
3077
3109
|
};
|
|
@@ -3233,7 +3265,7 @@ function evaluateContextRule(pathBytes, opCode, operandData, groupIndex, ruleInd
|
|
|
3233
3265
|
const value = contextValueToWord(contextValue);
|
|
3234
3266
|
let result;
|
|
3235
3267
|
let ctxOperand;
|
|
3236
|
-
if ((opCode
|
|
3268
|
+
if (isContextOp(opCode)) {
|
|
3237
3269
|
const operand = resolveContextOperand(operandData, context);
|
|
3238
3270
|
if (typeof operand !== "bigint") return {
|
|
3239
3271
|
code: "MISSING_CONTEXT",
|
|
@@ -3242,7 +3274,7 @@ function evaluateContextRule(pathBytes, opCode, operandData, groupIndex, ruleInd
|
|
|
3242
3274
|
operandData: bytesToHex(operandData),
|
|
3243
3275
|
typeCode: operand.ctxTypeCode
|
|
3244
3276
|
};
|
|
3245
|
-
result = value
|
|
3277
|
+
result = applyOperator(opCode, value, 32n, hexToBytes(bigintToHex(operand)), propertyInfo.typeCode);
|
|
3246
3278
|
ctxOperand = operand;
|
|
3247
3279
|
} else result = applyOperator(opCode, value, 32n, operandData, propertyInfo.typeCode);
|
|
3248
3280
|
if (!result) return {
|
|
@@ -3261,6 +3293,6 @@ const PolicyEnforcer = {
|
|
|
3261
3293
|
enforce
|
|
3262
3294
|
};
|
|
3263
3295
|
//#endregion
|
|
3264
|
-
export { CallciumError, ContextProperty, Descriptor, DescriptorCoder,
|
|
3296
|
+
export { CallciumError, ContextProperty, Descriptor, DescriptorCoder, Op, PolicyBuilder, PolicyCoder, PolicyEnforcer, PolicyFormat, PolicyValidator, PolicyViolationError, Quantifier, Scope, TypeCode, ValidationError, arg, baseFee, blockNumber, blockTimestamp, bytesToHex, chainId, findContextProperty, gasPrice, hexToBytes, isContextOp, isLengthOp, isOpAllowed, isQuantifier, lookupContextProperty, lookupOp, lookupQuantifier, lookupScope, lookupTypeCode, msgSender, msgValue, parsePathSteps, txOrigin };
|
|
3265
3297
|
|
|
3266
3298
|
//# sourceMappingURL=index.js.map
|