Sitelet https://github.com/formancehq/numscript/tags
Skip to content

Tags: formancehq/numscript

Tags

v0.1.1

Toggle v0.1.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(vm): release the store when Exec returns so a reused VM does not …

…retain it (#211)

v0.1

Toggle v0.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat: compiler and register VM (#199)

Refactored numscript as a register-based bytecode vm

v0.0.26

Toggle v0.0.26's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat: replace the funds execution engine with internal/funds (#190)

* refactor: extract the funds engine into internal/funds

Moves the funds queue, the balance cache, the value validators/parsers and the
asset-scaling helpers out of internal/interpreter into a standalone
internal/funds package, behind a RunState type. The interpreter becomes a
consumer of it rather than the owner. This is the shared substrate the
forthcoming bytecode VM needs: it must execute the same funds semantics without
depending on the tree-walking interpreter.

  internal/funds/funds.go    RunState: the source queue, the balance cache,
                             mark/rewind, postings
  internal/funds/values.go   account/asset/color/scope validators and parsers
  internal/funds/scaling.go  was interpreter/asset_scaling.go
  internal/funds/metadata.go AccountsMetadata

Behavior changes, each pinned by a spec in this commit:

  neg-max-dest        a negative amount in a destination max clause now fails
                      with NegativeAmountErr instead of emitting a posting.

  scaling-with-oneof  a oneof branch that falls short now discards its
                      scaled-swap postings, via RunState's mark/rewind.

  midscript-balance-after-credit
                      a mid-script balance() read is no longer masked by an
                      earlier write to the same account. The old
                      InternalBalances.has() could not tell "fetched from the
                      store" from "created by a write", so crediting @alice and
                      then reading balance(@alice) skipped the fetch and
                      reported only what the script sent, dropping the starting
                      balance. funds.balanceEntry now carries baseLoaded
                      separately from the amount: Has() reports false for an
                      entry holding only a write delta, and Prewarm folds the
                      fetched base into that delta instead of overwriting it.

The balance() change is not breaking: mid-script calls are gated behind
experimental-mid-script-function-call. balance() inside a vars block is
unaffected, since vars resolve before execution and no write can mask them.

Ledger implementors will see one store-call difference: the balance read is now
a lazy fetch where there was none, so GetBalancesCalls in TestMidscriptBalance
goes from nil to a single fetch.

internal/specs_format exports four helpers that were package-private
(MergeBalances, EndBalances, GetMovements, CompareMovements). They have no
consumer in this commit; the differential-testing harness will use them.

* fix: keep real balance values during dependency resolution

The injected getBalance for dependency resolution returned zero, on the
stated assumption that a balance() yields a Monetary and so cannot name an
account. get_amount breaks that assumption: it turns a balance into a number,
and an interpolated account can be built from that number.

So for

  vars {
    monetary $b = balance(@treasury, USD)
    number $id = get_amount($b)
  }
  send [USD 1] (
    source = @user:$id allowing unbounded overdraft
    destination = @out
  )

resolution reported a write to user:0 while execution posted from user:100 —
a ledger pre-locking or prefetching from the resolved set would act on the
wrong account. main is unaffected: there, resolution and execution shared one
getBalance that returned the fetched value.

Returns the fetched amount instead, and adds the case to
TestResolveDependenciesCoversRuntime, which asserts resolution covers what
execution touches. Confirmed the case fails without the fix.

The differential harness cannot catch this class: internal/gen emits no
account interpolation.

* fix: fail closed on a negative asset-scaling conversion

ForcePosting treated any non-positive amount as a no-op. FindScalingSolution
can return a negative conversion when the source holds a negative balance at
one scale, and dropping that leg while posting the positive ones moves money
one way without the compensating move back.

For @ACC1 holding EUR/2 -100 and EUR/1 20:

  send [EUR 1] (
    source = @ACC1 with scaling through @swap
    destination = @DesT
  )

the solution is the pair (-100, 20), netting the 1 EUR asked for. Discarding
the negative leg left acc1 paying EUR/1 20 — 2 EUR — to move 1 EUR, with
@swap keeping the difference, and the script reported success.

main fails this script: the negative conversion became a negative posting and
checkPostingInvariants rejected it. That check still exists here, but the
posting no longer reaches it, because ForcePosting discarded it first.

ForcePosting now returns ErrNegativePosting for a negative amount (zero stays
a no-op), and the interpreter maps it to the same InternalError, so the
user-visible behavior matches main exactly, error message included.

This is a fail-closed path, not a computed result: the underlying question of
whether FindScalingSolution should produce such a solution at all is left
alone deliberately — answering it would change the scaling semantics rather
than restore the invariant.

* fix: clamp a negative destination max clause to zero instead of erroring

Reverts the funds-engine rewrite's neg-max-dest change. A negative cap on a
destination max clause now behaves like the source-side one
(tryTakingUpTo/NonNeg): clamped to zero rather than NegativeAmountErr, matching
ledger's own gap on this shape (oracle/DIVERGENCES.md #4) and restoring what
internal/difftest's TestDestinationSideNegativeMaxTolerated already expects.

* fix: keep the scaling prefetch from masking other assets' balances

AccountBalances folded the base of every tracked entry of the account,
against the interpreter's zero-backed store. A delta-only entry for an
asset outside the scaled family got stamped base-loaded with a zero
base, so a later mid-script balance() skipped its fetch and reported
only the script's own writes. Filter to the base-asset family the
scaling prefetch actually covers; pinned by the
scaling-prefetch-midscript-balance fixture.

v0.0.25

Toggle v0.0.25's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix: remove space from artifact (#187)

v0.0.24

Toggle v0.0.24's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat: feature flag syntax (#120)

* feat: feature flag syntax

* feat: change syntax

* feat: reject invalid features

* feat: add static check of unknown features

* feat: more defensive args handling

* fix: fix typo

v0.0.23

Toggle v0.0.23's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
chore: update nix deps (#111)

Signed-off-by: Sylvain Rabot <sylvain@formance.com>

v0.0.22

Toggle v0.0.22's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix: fix *.include specs (#108)

v0.0.21

Toggle v0.0.21's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat: expose MissingFundsErr (#107)

v0.0.20

Toggle v0.0.20's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat: MCP first MVP (#97)

v0.0.19

Toggle v0.0.19's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
test: fix false positive tests (#89)