This project is a WebAssembly (WASM) port of the formancehq/numscript CLI, enabling you to run Numscript execution in any WASM-compatible environment. Originally forked from the official repository, it now provides a standalone WASM binary that maintains full compatibility with the original CLI functionality.
Numscript is a Domain-Specific Language (DSL) designed to help you model complex financial transactions, replacing complex and error-prone custom code with easy-to-read, declarative scripts. Originally developed by Formance, Numscript is used to express financial transactions within the Formance ledger system.
The language provides:
- Declarative syntax for modeling financial operations
- Built-in validation for transaction integrity
- Account management with metadata support
- Variable substitution for dynamic scripts
- Feature flags for experimental functionality
You can try Numscript online at playground.numscript.org.
You'll need a WebAssembly (WASM) runtime to execute the numscript-wasm binary. This guide uses Wasmtime, but you can also use other WASM runtimes like Wasmer.
Install Wasmtime:
curl https://wasmtime.dev/install.sh -sSf | bashDownload the WASM binary from the latest release for your platform.
The CLI provides two commands: version and run.
Display the current version of the CLI:
wasmtime numscript.wasm versionOutput:
# If you are using the released binary this will print the real app version:
v0.1.0
# Otherwise will print dev:
devExecute a Numscript with the provided input data. The command reads JSON input from stdin containing the script, variables, account metadata, balances, and feature flags.
The input JSON must follow this structure:
| Field | Type | Required | Description |
|---|---|---|---|
script |
string | ✅ | The Numscript code to execute |
variables |
object | ❌ | Variables |
metadata |
object | ❌ | Account metadata |
balances |
object | ✅ | Current account balances. Example below. |
featureFlags |
object | ❌ | Experimental features to enable (empty objects as values). Example below |
Is an object containing the account name and their respective assets and balances. Ex:
"balances": {
"foo": {
"USD/2": 200,
"EUR/2": 100
},
"bar": {
"BRL/2": 200,
"JPY/2": 100
}
},Assets use the format CURRENCY/PRECISION:
USD/2= US Dollars with 2 decimal placesEUR/2= Euros with 2 decimal placesBTC/8= Bitcoin with 8 decimal places
Is an object containing the name of the feature flag you want to use with an empty object as their value. Ex:
"featureFlags": {
"experimental-oneof": {},
"experimental-get-amount-function": {},
"experimental-mid-script-function-call": {}
}Numscript does not have an official list of feature flags, but you can see the source code and the documentation with the experimental features usage
Simple account-to-account transfer:
- Create an input file (
example.json):
{
"script": "send [USD/2 100] (\n source = @foo\n destination = @bar\n)",
"balances": {
"foo": {
"USD/2": 200,
"EUR/2": 100
}
},
"variables": {},
"metadata": {},
"featureFlags": {}
}- Execute the script:
wasmtime numscript.wasm run < example.json- Expected output (JSON format):
{
"postings": [
{
"source": "foo",
"destination": "bar",
"asset": "USD/2",
"amount": 100
}
],
"txMeta": {},
"accountsMeta": {}
}- Input File: (
example.json):
{
"script": "vars { account $user monetary $fee portion $tax } send $fee (source = $user destination = { $tax to @platform:tax remaining to @platform:revenue })",
"balances": {
"users:1234": {
"USD/2": 10000
}
},
"variables": {
"user": "users:1234",
"fee": "USD/2 100",
"tax": "20%"
},
"metadata": {},
"featureFlags": {
"experimental-oneof": {},
"experimental-get-amount-function": {},
"experimental-mid-script-function-call": {}
}
}- Execute the script:
wasmtime numscript.wasm run < example.json- Expected output (JSON format):
{
"postings": [
{
"source": "users:1234",
"destination": "platform:tax",
"amount": 20,
"asset": "USD/2"
},
{
"source": "users:1234",
"destination": "platform:revenue",
"amount": 80,
"asset": "USD/2"
}
],
"txMeta": {},
"accountsMeta": {}
}- Input File: (
example.json):
{
"script": "vars { account $order account $merchant = meta($order, \"merchant\") portion $commission = meta($merchant, \"commission\") } send [USD/2 *] ( source = $order destination = { $commission to @platform:fees remaining to $merchant })",
"balances": {
"orders:2345": {
"USD/2": 1000
}
},
"variables": {
"order": "orders:2345"
},
"metadata": {
"orders:2345": {
"merchant": "merchants:1234"
},
"merchants:1234": {
"commission": "15%"
}
},
"featureFlags": {
"experimental-oneof": {},
"experimental-get-amount-function": {},
"experimental-mid-script-function-call": {}
}
}- Execute the script:
wasmtime numscript.wasm run < example.json- Expected output (JSON format):
{
"postings": [
{
"source": "orders:2345",
"destination": "platform:fees",
"amount": 150,
"asset": "USD/2"
},
{
"source": "orders:2345",
"destination": "merchants:1234",
"amount": 850,
"asset": "USD/2"
}
],
"txMeta": {},
"accountsMeta": {}
}If you want to use experimental features, you need to enable them by adding their respective feature flag:
- Input File: (
example.json):
{
"script": "vars { monetary $mon = [USD/2 100] number $n = get_amount($mon) } send [USD/2 $n] (source = oneof { @foo @bar } destination = @baz)",
"balances": {
"foo": {
"USD/2": 99
},
"bar": {
"USD/2": 100
}
},
"variables": {},
"metadata": {},
"featureFlags": {
"experimental-oneof": {},
"experimental-get-amount-function": {},
"experimental-mid-script-function-call": {}
}
}- Execute the script:
wasmtime numscript.wasm run < example.json- Expected output (JSON format):
{
"postings": [
{
"source": "bar",
"destination": "baz",
"amount": 100,
"asset": "USD/2"
}
],
"txMeta": {},
"accountsMeta": {}
}The CLI will exit with status code 1 and write error messages to stderr if:
- The input JSON is malformed
- The Numscript has parsing errors
- The execution fails due to insufficient balances or other runtime errors
Example error output:
Exception: Not enough funds. Needed [USD/2 100] (only [USD/2 99] available)
This project maintains the same license as the original formancehq/numscript repository.
This is a fork focused on WASM compatibility. For core Numscript language contributions, please consider contributing to the upstream formancehq/numscript repository.