@crediolabs/policy-synth 0.1.8 → 0.1.9
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/adapters/interpreter/adapter.js +21 -3
- package/dist/adapters/oz/adapter.js +8 -0
- package/dist/ir/types.d.ts +9 -0
- package/dist/predicate/encode.js +9 -0
- package/dist/review-card/builder.js +2 -0
- package/dist/review-card/cross-check.js +2 -0
- package/dist/synth/compose-from-recording.js +89 -0
- package/dist/synth/deny-cases.js +89 -1
- package/dist/synth/evaluate.js +49 -0
- package/dist/types.d.ts +8 -0
- package/dist-cjs/adapters/interpreter/adapter.js +21 -3
- package/dist-cjs/adapters/oz/adapter.js +8 -0
- package/dist-cjs/ir/types.d.ts +9 -0
- package/dist-cjs/predicate/encode.js +9 -0
- package/dist-cjs/review-card/builder.js +2 -0
- package/dist-cjs/review-card/cross-check.js +2 -0
- package/dist-cjs/synth/compose-from-recording.js +89 -0
- package/dist-cjs/synth/deny-cases.js +89 -1
- package/dist-cjs/synth/evaluate.js +49 -0
- package/dist-cjs/types.d.ts +8 -0
- package/package.json +1 -1
- package/src/adapters/interpreter/adapter.ts +20 -4
- package/src/adapters/oz/adapter.ts +8 -0
- package/src/ir/types.ts +8 -0
- package/src/predicate/encode.ts +9 -0
- package/src/review-card/builder.ts +2 -0
- package/src/review-card/cross-check.ts +2 -0
- package/src/synth/compose-from-recording.ts +87 -0
- package/src/synth/deny-cases.ts +86 -1
- package/src/synth/evaluate.ts +41 -0
- package/src/types.ts +10 -0
package/src/synth/evaluate.ts
CHANGED
|
@@ -216,6 +216,33 @@ function evalCompare(
|
|
|
216
216
|
return evalArgEq(op, actual, right, ctx)
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
+
// --- step 4c: call_arg_len: the length of a vec-typed argument as a u32.
|
|
220
|
+
// Fails closed on a non-vec arg, an absent arg, or a non-u32 literal.
|
|
221
|
+
if (left.kind === 'call_arg_len') {
|
|
222
|
+
const actual = ctx.args[left.index]
|
|
223
|
+
if (!actual || actual.type !== 'vec') return { permit: false, reason: 'ARG_MISMATCH' }
|
|
224
|
+
if (right.kind !== 'literal_u32') return { permit: false, reason: 'ARG_MISMATCH' }
|
|
225
|
+
return actual.value.length === right.value
|
|
226
|
+
? { permit: true }
|
|
227
|
+
: { permit: false, reason: 'ARG_MISMATCH' }
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// --- step 4d: call_arg_field: the value of a field in the map at element i
|
|
231
|
+
// of the vec at argument index. Fails closed on a non-vec arg, an
|
|
232
|
+
// out-of-range element, a missing field, a non-map element, or a type
|
|
233
|
+
// mismatch between the field ScVal and the literal leaf.
|
|
234
|
+
if (left.kind === 'call_arg_field') {
|
|
235
|
+
const actual = ctx.args[left.index]
|
|
236
|
+
if (!actual || actual.type !== 'vec') return { permit: false, reason: 'ARG_MISMATCH' }
|
|
237
|
+
const element = actual.value[left.element]
|
|
238
|
+
if (!element || element.type !== 'map') return { permit: false, reason: 'ARG_MISMATCH' }
|
|
239
|
+
if (!Array.isArray(element.value)) return { permit: false, reason: 'ARG_MISMATCH' }
|
|
240
|
+
const entry = element.value.find((e) => e.key === left.field)
|
|
241
|
+
if (!entry) return { permit: false, reason: 'ARG_MISMATCH' }
|
|
242
|
+
if (op === 'eq') return evalArgEq(op, entry.val, right, ctx)
|
|
243
|
+
return evalArgOrderedCompare(op, entry.val, right)
|
|
244
|
+
}
|
|
245
|
+
|
|
219
246
|
// --- step 6: AMOUNT_BOUND ---
|
|
220
247
|
if (left.kind === 'amount' && op !== 'eq') {
|
|
221
248
|
return evalAmountCompare(op, left.token, right, ctx)
|
|
@@ -383,6 +410,20 @@ function resolveLeaf(leaf: PredicateLeaf, ctx: EvalContext): ScVal | undefined {
|
|
|
383
410
|
return { type: 'symbol', value: ctx.fn }
|
|
384
411
|
case 'call_arg':
|
|
385
412
|
return ctx.args[leaf.index]
|
|
413
|
+
case 'call_arg_len':
|
|
414
|
+
// No direct ScVal projection: the length is an integer the comparator
|
|
415
|
+
// resolves against the right-hand literal. Returning undefined keeps
|
|
416
|
+
// the `in` membership path structurally informed (no haystack match).
|
|
417
|
+
return undefined
|
|
418
|
+
case 'call_arg_field': {
|
|
419
|
+
const actual = ctx.args[leaf.index]
|
|
420
|
+
if (!actual || actual.type !== 'vec') return undefined
|
|
421
|
+
const element = actual.value[leaf.element]
|
|
422
|
+
if (!element || element.type !== 'map') return undefined
|
|
423
|
+
if (!Array.isArray(element.value)) return undefined
|
|
424
|
+
const entry = element.value.find((e) => e.key === leaf.field)
|
|
425
|
+
return entry ? entry.val : undefined
|
|
426
|
+
}
|
|
386
427
|
case 'amount':
|
|
387
428
|
case 'window_spent':
|
|
388
429
|
case 'oracle_price':
|
package/src/types.ts
CHANGED
|
@@ -145,6 +145,16 @@ export type PredicateLeaf =
|
|
|
145
145
|
| { kind: 'call_contract' }
|
|
146
146
|
| { kind: 'call_fn' }
|
|
147
147
|
| { kind: 'call_arg'; index: number }
|
|
148
|
+
// Length of a vec-typed argument as a u32. Binds the OUTER vec length so
|
|
149
|
+
// a caller cannot append a new element to defeat a per-element pin.
|
|
150
|
+
// Paired with `call_arg_field` per element - pinning only the field leaves
|
|
151
|
+
// an element-append vulnerability; this leaf closes it.
|
|
152
|
+
| { kind: 'call_arg_len'; index: number }
|
|
153
|
+
// Value of `field` in the map at `element` of the vec at argument `index`.
|
|
154
|
+
// Fixed-arity: index, element, field. The leaf is resolved against the
|
|
155
|
+
// recorded ScVal type. A non-vec arg, missing element, missing field, or
|
|
156
|
+
// type mismatch all DENY (fail-closed).
|
|
157
|
+
| { kind: 'call_arg_field'; index: number; element: number; field: string }
|
|
148
158
|
// `call_sub_invocation[i]` is NOT in v1 grammar. OZ `Policy::enforce`
|
|
149
159
|
// receives one `Context`, not a sub-invocation tree; sub-invocations live under
|
|
150
160
|
// `InvokerContractAuthEntry::Contract(SubContractInvocation)`, not in the
|