Write a small contract, compile it to CLVM, inspect the generated program, and execute it locally. This walkthrough uses the experimental compiler 0.1.0-m3.8b, language 0.1, ABI 1. It uses only released features; FOR/NEXT is unavailable in that release. The development loop tutorial targets the newer source-built compiler.
0xBASIC programs describe conditions for spending Chia coins. They do not print messages or prompt for keyboard input. Our first example returns a condition requiring a minimum block height. It is a learning example, not an ownership-protected payment contract.
Download the Windows ZIP or Linux tar.gz from the experimental release, verify its adjacent SHA-256 checksum, and extract it into a new directory. See the release record for tested operating-system versions. No Rust or Python installation is needed for this walkthrough.
Open a terminal in the extracted directory. The executable is:
| Platform | Executable |
|---|---|
| Windows PowerShell | ./bin/0xbasic.exe |
| Native Linux | ./bin/0xbasic |
Commands below use the Linux spelling. On Windows, replace ./bin/0xbasic with ./bin/0xbasic.exe in every command. Keep the rest of each command unchanged. Linux extraction must preserve the executable permission.
./bin/0xbasic --version
./bin/0xbasic --help
Expect compiler version 0.1.0-m3.8b. These two standalone commands do not take --json; the other commands below use it for structured results.
In a plain-text editor, create hello.bas in the extracted directory. Save it as UTF-8, not hello.bas.txt.
CONTRACT HeightLock(earliestHeight AS INTEGER)
' Reject negative heights before returning a condition.
ASSERT earliestHeight >= 0
EMIT ASSERT_HEIGHT_ABSOLUTE(earliestHeight)
END CONTRACTHere is what each part means:
CONTRACT ... END CONTRACTdefines the single contract in this file.earliestHeight AS INTEGERdeclares a fixed parameter, supplied when compiling the bound puzzle. It is not a keyboard prompt.- An apostrophe begins a comment.
REMcomments are also supported. ASSERTrequires a BOOLEAN expression to be true when the program executes; otherwise execution fails.ASSERT_HEIGHT_ABSOLUTE(...)constructs a height condition. It requires an INTEGER in0..4294967295.EMITappends that condition to the program's result. It does not contact a node or wait for a block.
Names and keywords are case-insensitive. Use one statement per line and structured END blocks; there are no line numbers or colon-separated statements.
./bin/0xbasic check hello.bas --json
Expect "ok": true, an empty diagnostics array, and a result naming the contract. Checking verifies syntax and types without needing a concrete height or executing the program. On an error, ok is false and the diagnostic identifies the problem; fix it before building.
Create hello.bindings.json beside the source:
{"earliestHeight":"100"}The quotes around "100" are required: INTEGER values in binding/solution JSON are decimal strings, not JSON numbers. The field name must match the declared parameter, case-insensitively.
./bin/0xbasic build hello.bas --bindings hello.bindings.json --out hello-build --json
Expect "ok": true. hello-build must not already exist; the compiler refuses to overwrite it. For another experiment, use a new output name such as hello-build-2.
The new directory contains:
| File | Purpose |
|---|---|
template.clvm |
Binary serialized CLVM before the fixed parameters are bound |
template.hex |
The same template bytes represented as readable hexadecimal |
puzzle.clvm |
Binary CLVM with the fixed height bound into it |
puzzle.hex |
The bound puzzle bytes in hexadecimal |
manifest.json |
Compiler/profile identities, schemas, normalized bindings, filenames and hashes |
The bound puzzle is the program whose tree hash identifies a coin's puzzle. The template and bound puzzle have different roles. Keep the source, binding file and complete artifact directory together for your records.
Yes—the compiler can show its generated CLVM. Run:
./bin/0xbasic explain hello.bas --stage clvm --bindings hello.bindings.json --json
Look in result.representation.template and result.representation.puzzle. Each includes serialized hex, a serialized-byte program_sha256, a CLVM tree_hash, and a flat tree described by root and nodes.
In that node list, {"atom":"..."} contains atom bytes as hex. {"pair":[a,b]} refers to two node indexes. This exposes the generated CLVM structure without requiring an external disassembler. The generated hex and hashes match the corresponding build artifacts for the same source and bindings.
explain regenerates the representation from source and bindings; it does not open hello-build/manifest.json. To inspect the saved files directly, open puzzle.hex and manifest.json in a text editor. Do not open binary .clvm files expecting source text. The released CLI does not provide a separate saved-bytecode disassembly command or a conventional symbolic CLVM listing.
You can also inspect earlier compiler stages:
./bin/0xbasic explain hello.bas --stage ast --json
./bin/0xbasic explain hello.bas --stage ir --json
ast shows parsed syntax; ir shows the checked intermediate representation. These inspection commands do not execute the program or write build artifacts.
./bin/0xbasic run hello-build/manifest.json --json
Expect "ok": true, "validation": "clvm-execution-only", a measured cost, and this raw result tree:
{"pair":[{"pair":[{"atom":"53"},{"pair":[{"atom":"64"},{"atom":""}]}]},{"atom":""}]}As a list of decimal values, that is ((83 100)): condition opcode 83 (ASSERT_HEIGHT_ABSOLUTE) with height 100. 53 and 64 above are hexadecimal atoms; the empty atom is the list terminator.
This is the program's output condition list, not a disassembly of the compiled puzzle. The local runner does not know the current blockchain height or confirm a spend. It can successfully return the height condition even when an actual chain would reject spending the coin too early.
Our contract declares no SOLUTION fields, so no solution file is needed. For contracts that do, run accepts --solution FILE for JSON values or --solution-hex FILE for a serialized CLVM solution written in hex.
These are the released language building blocks. Consult the historical language specification for exact signatures and restrictions.
| Area | Supported syntax or names |
|---|---|
| Structure | CONTRACT ... END CONTRACT; FUNCTION ... AS type ... END FUNCTION; function RETURN |
| Inputs | Fixed contract parameters; initial SOLUTION name AS type declarations for spender-supplied values |
| Local values | Initialized DIM; reassignment to DIM locals; compile-time CONST (no calls in constant expressions) |
| Branches and checks | Multiline IF ... THEN, ELSEIF, ELSE, END IF; ASSERT; EMIT in contracts |
| Arithmetic | INTEGER unary +/-, addition, subtraction and multiplication |
| Comparisons and logic | =, <>; INTEGER <, <=, >, >=; BOOLEAN TRUE, FALSE, NOT, short-circuit AND/OR |
| Scalar types | INTEGER, BOOLEAN, BYTES, STRING, AMOUNT, PUZZLEHASH, PUBLICKEY |
| Structured types | LIST OF T, PAIR OF (A, B); internal CONDITION values |
| Byte/string functions | BYTE_LENGTH, CONCAT, SHA256, UTF8, STRING_FROM_UTF8 |
| Integer encodings | INT_BYTES, INT_FROM_BYTES, U32BE, U64BE |
| Domain conversions | AS_AMOUNT, AMOUNT_VALUE, AS_PUZZLEHASH, HASH_BYTES, AS_PUBLICKEY, KEY_BYTES |
| Collections | List literals such as [1, 2]; PAIR, FIRST, REST, CONS, LIST_LENGTH |
| Condition constructors | ASSERT_HEIGHT_ABSOLUTE, ASSERT_MY_AMOUNT, CREATE_COIN, AGG_SIG_ME |
Functions are pure and nonrecursive. Fixed parameters, SOLUTION fields and function parameters are immutable. There are no implicit conversions between distinct types. CONDITION cannot be an external fixed parameter or solution field. String text is quoted; byte literals use 0x followed by pairs of hex digits.
Not supported by this released compiler: FOR/NEXT or other loops, user recursion, PRINT, interactive INPUT, division/remainder, floating point, GOTO, SUB, imports/modules, runtime file I/O, or wallet/signing/submission commands. A design proposal is not an executable feature.
- Inspect it: examine the manifest, hex and generated CLVM tree as shown above.
- Test it locally: run it with different solution values where declared, and inspect its output and execution cost. Changing a fixed parameter requires a new build.
- Compare builds: preserve original artifacts and compare bytes and puzzle identities using the rebuild walkthrough.
- Test actual spends in isolation: use the separate simulator harness, which handles signing and confirmation in test scenarios.
- Develop a real contract: extend the example with appropriate authorization and payment conditions; the signed-payment tutorial is the next step. Funding a coin, signing, paying fees, submitting and confirming a spend require tools outside this CLI. Rebuilding a program does not change an existing coin's puzzle.
This height-only example does not require an owner's signature or specify where funds must go. Do not treat it as a secure payment or savings contract. Compilation and local execution alone do not establish production readiness.
The source, bindings and command blocks were checked with the published Windows experimental executable. The generated CLVM bytes/hashes match the saved artifacts, and local execution returns the exact condition tree shown above. This tutorial documents existing released behavior; it introduces no new compiler feature or native Linux test requirement.