Skip to content

Latest commit

 

History

History
261 lines (196 loc) · 7.05 KB

File metadata and controls

261 lines (196 loc) · 7.05 KB

Binding Validation

Generated TypeScript bindings can become stale when the underlying Soroban contract ABI changes. Glassbox detects this automatically by embedding a cryptographic ABI hash into every generated file and comparing it against the current source ABI on demand.


How It Works

1. Metadata headers

Every file produced by glassbox generate-bindings begins with a structured comment block:

/* @glassbox-bindings-meta
 * abi-hash:    e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
 * contract-id: CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQAHHAGCN4B2
 * generated:   2026-05-30T12:00:00Z
 * glassbox:    1.2.3
 */
Field Description
abi-hash SHA-256 of the canonical JSON representation of the contract spec
contract-id Stellar contract ID (empty when not provided at generation time)
generated RFC 3339 UTC timestamp of when the bindings were generated
glassbox Version of the glassbox binary that generated the bindings

The ABI hash is computed by serialising the contract spec to the canonical JSON format (the same output as glassbox abi --format json) and taking its SHA-256 digest. Because the canonical JSON is deterministic, the hash changes if and only if the ABI changes — regardless of whether the source was a WASM binary or a JSON/XDR spec file.

2. Staleness detection

glassbox check-bindings reads the abi-hash field from each generated file and compares it against the hash computed from the current source ABI. A file is reported as:

Status Meaning
fresh The stored hash matches the current ABI — no action needed
stale The stored hash differs — the ABI has changed since generation
missing The file does not exist in the output directory
no-metadata The file exists but has no @glassbox-bindings-meta header (generated by an older glassbox version)

Generating Bindings

Use glassbox generate-bindings as usual. Metadata headers are embedded by default:

# From a compiled WASM binary
glassbox generate-bindings contract.wasm \
  --output ./src/generated \
  --package my-contract

# From a JSON ABI file
glassbox generate-bindings \
  --spec-file contract-abi.json \
  --output ./src/generated \
  --package my-contract

To opt out of metadata embedding (e.g. for reproducible snapshot tests):

# Not recommended for production workflows — disables staleness detection
glassbox generate-bindings contract.wasm --output ./src/generated --no-embed-metadata

Checking for Stale Bindings

Basic check

# Check against a WASM binary
glassbox check-bindings contract.wasm --output ./src/generated

# Check against a JSON ABI file
glassbox check-bindings --spec-file contract-abi.json --output ./src/generated

Example output when bindings are up-to-date:

Binding directory : ./src/generated
Source ABI hash   : e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

  ✓  types.ts                         fresh
  ✓  metadata.ts                      fresh
  ✓  client.ts                        fresh
  ✓  Glassbox-integration.ts          fresh
  ✓  index.ts                         fresh
  ✓  package.json                     fresh
  ✓  README.md                        fresh

[OK] All bindings are up-to-date.

Example output when bindings are stale:

Binding directory : ./src/generated
Source ABI hash   : a1b2c3d4e5f6...

  ✗  types.ts                         stale
       ABI hash mismatch: stored=e3b0c442 current=a1b2c3d4
  ✗  metadata.ts                      stale
  ...

[STALE] 7 file(s) are out-of-date. Run with --regenerate to update.

JSON output

Pass --json to get a machine-readable report:

glassbox check-bindings --spec-file abi.json --output ./src/generated --json
{
  "outputDir": "./src/generated",
  "sourceABIHash": "a1b2c3d4...",
  "isStale": true,
  "staleCount": 7,
  "files": [
    {
      "path": "types.ts",
      "status": "stale",
      "storedHash": "e3b0c442...",
      "currentHash": "a1b2c3d4...",
      "generatedAt": "2026-05-30T12:00:00Z",
      "reason": "ABI hash mismatch: stored=e3b0c442 current=a1b2c3d4"
    }
  ]
}

Exit codes

Code Meaning
0 All bindings are up-to-date
1 One or more bindings are stale, missing, or have no metadata
2 A usage or validation error occurred

Auto-Regenerating Stale Bindings

Pass --regenerate to automatically regenerate any stale or missing files:

glassbox check-bindings contract.wasm \
  --output ./src/generated \
  --regenerate \
  --package my-contract \
  --network testnet

Regeneration flags (only used when --regenerate is set):

Flag Default Description
--package input filename npm package name for the generated bindings
--network testnet Stellar network (testnet, mainnet, futurenet)
--runtime node Target runtime: node, browser, or universal
--contract-id (empty) Stellar contract ID to embed
--debug-metadata false Include ABI debug metadata wrappers

Recommended Workflow

Local development

Add a pre-commit check or a Makefile target:

.PHONY: check-bindings
check-bindings:
	glassbox check-bindings contract.wasm \
	  --output ./src/generated \
	  --package my-contract

.PHONY: update-bindings
update-bindings:
	glassbox check-bindings contract.wasm \
	  --output ./src/generated \
	  --package my-contract \
	  --regenerate

CI pipeline

Use the non-zero exit code to fail the build when bindings are stale:

# GitHub Actions example
- name: Check TypeScript bindings are up-to-date
  run: |
    glassbox check-bindings contract.wasm \
      --output ./src/generated \
      --json | tee binding-report.json
    # Exit code 1 fails the step automatically.

Pre-commit hook

#!/bin/sh
# .git/hooks/pre-commit
glassbox check-bindings contract.wasm --output ./src/generated
if [ $? -ne 0 ]; then
  echo "TypeScript bindings are stale. Run 'make update-bindings' to regenerate."
  exit 1
fi

Troubleshooting

"no @glassbox-bindings-meta header found"

The binding files were generated by an older version of glassbox that did not embed metadata headers. Regenerate them:

glassbox generate-bindings contract.wasm --output ./src/generated --package my-contract

Hash mismatch after a no-op ABI change

If the ABI hash changes even though you believe the contract interface is unchanged, inspect the canonical JSON to see what differs:

glassbox abi --format json contract.wasm

Minor changes such as reordering functions, adding documentation strings, or changing struct field order will all produce a different hash.

Bindings are always reported as stale in CI

Ensure the same WASM binary (or spec file) is used for both generation and validation. If the WASM is rebuilt between steps, the ABI hash will differ even if the interface is logically identical.