Skip to content

feat: add first-class assert action#20

Merged
Agusx1211 merged 3 commits into
masterfrom
feat/assert-action
Jun 29, 2026
Merged

feat: add first-class assert action#20
Agusx1211 merged 3 commits into
masterfrom
feat/assert-action

Conversation

@Agusx1211

Copy link
Copy Markdown
Member

Summary

Adds a first-class assert primitive action. Today, asserting an on-chain invariant requires a hacky "assertion template" — an empty-body template whose skip_condition is the invariant, relying on the engine's post-execution check to throw. It's indirect, verbose, and the error can't say which invariant failed.

The assert action evaluates a comparison and throws a clear error if it doesn't hold (no broadcast, ever).

API

type: assert with arguments:

  • ACTUAL comes from either to (+ signature, optional values) → eth_call, or actual → any value resolver
  • Exactly one comparator key: eq, neq, gt, lt, gte, lte → the EXPECTED value
  • Optional message included in the error output

Comparison composes the existing call and basic-arithmetic resolvers. On failure it throws assert failed[: message]: <describe> (actual=…, expected=…, op=…).

- type: assert
  name: check-deposit-manager
  arguments:
    to: "{{some-proxy}}"
    signature: "depositManager() returns (address)"
    eq: "{{expected-deposit-manager}}"

Changes

  • src/lib/types/actions.tsAssertAction type, registered as a primitive
  • src/lib/core/engine.ts — execution logic; enforces exactly one comparator (rejects zero or multiple)
  • src/lib/core/__tests__/assert-action.spec.ts — 25 tests
  • README.md — docs section
  • dist/ — rebuilt canonical artifacts

Testing

  • Assert suite: 25/25 pass
  • Full suite: 605/605 pass

🤖 Generated with Claude Code

Agusx1211 and others added 3 commits June 29, 2026 18:38
Today, asserting an on-chain invariant in a job requires a hacky
"assertion template" — a template whose body is empty and whose
skip_condition is the invariant, relying on the engine's post-execution
check to throw. It's indirect, verbose, and the error can't even say
which invariant failed.

A first-class assert action fixes this: it evaluates a condition and
throws a clear error if it doesn't hold.

API: type: assert with fields:
- to (AddressValue) + signature (string) + optional values (array)
  → ACTUAL = result of eth_call (call value resolver)
- actual (Value) → ACTUAL = that value resolved
- Exactly one comparator key: eq, neq, gt, lt, gte, lte → EXPECTED
- Optional message (string) for the error

Semantics: resolve ACTUAL and EXPECTED, compare
ACTUAL <comparator> EXPECTED via basic-arithmetic (composing existing
resolvers). If FALSE, throw. If TRUE, succeed (no broadcast).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bring in the provenance, get-storage-at, and skip_if features now on
master, then clean-rebuild the canonical dist/ so it reflects the full
merged source. Also force-adds the compiled assert-action spec, which
the original change omitted (dist/ is gitignored, so new build outputs
must be added explicitly).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Agusx1211 Agusx1211 merged commit c7923d1 into master Jun 29, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant