Skip to content

Valid Code & Restrictions

Xian contracts are ordinary Python syntax inside a restricted execution model. The linter enforces that restricted subset before code is accepted.

Allowed Syntax

FeatureExampleNotes
assignmentx = 1
arithmetic+, -, *, /, //, %, **
comparisons==, !=, <, >, <=, >=, in, not in, is, is not
boolean logicand, or, not
if / elif / elseif x > 0:
for / whileloopsmetered like everything else
functionsdef f():top-level only
returnreturn value
assertassert ok, "message"main validation pattern
collectionslist, dict, tuple, set(), frozenset()set literals and set comprehensions are blocked
list comprehensions[x for x in items]generator expressions are not allowed
subscripts / slicesx[0], x[1:3]
importsimport currencymodule-level only for deployed contracts

Forbidden Syntax

FeatureError CodeWhy
try/except, with, lambda, ternary expressions, yield, yield from, nonlocal, @, set literals, set comprehensions, semicolons, one-line compound statementsE001blocked syntax in the sandbox or rejected to keep line-bucket metering predictable
names starting or ending with _E002blocks Python internals / escape paths
import inside a functionE003imports must be explicit and module-level
from x import yE004use import x then x.y
stdlib module importE005only deployed contracts and runtime modules are allowed
class definitionsE006contracts are module/function based
async functionsE007no async execution in contracts
invalid decoratorsE008only @export and @construct
multiple constructorsE009only one constructor allowed
multiple decorators on one functionE010single-decorator model
forbidden ORM kwargsE011runtime owns those names
tuple unpacking of ORM declarationsE012storage declarations must be explicit
no @export function presentE013contract needs a public API
forbidden builtin or reserved nameE014unsafe builtins and reserved identifiers are blocked
exported arg shadows ORM nameE015avoids confusing state collisions
invalid argument annotationE016exported args must use allowed types
missing export annotationE017exported args must be typed
invalid export return annotationE018export returns may only use allowed types
nested function definitionE019avoids closures and hidden state
parse errorE020ordinary syntax error
invalid decorator argumentsE021@export only supports typecheck=True/False; @construct takes no arguments
profile-blocked syntaxE022rejected by the active validation profile
profile-blocked builtinE023builtin is not supported by the active validation profile

Allowed Builtins

The current builtin allowlist is intentionally small:

text
Exception False None True abs all any ascii bin bool bytearray bytes chr
dict divmod filter float format frozenset hex int isinstance issubclass len
list map max min oct ord pow range reversed round set sorted str sum tuple zip

Everything else is treated as forbidden.

Allocation Guards

Allowed builtins are still bounded by deterministic runtime limits:

  • range(...) may create at most 131,072 entries.
  • bytes(n) and bytearray(n) may allocate at most 131,072 bytes.
  • string, bytes, bytearray, list, and tuple repetition with * may not exceed the same sequence or byte limits.
  • returned contract values may not exceed 131,072 bytes when serialized.
  • submitted contract source may not exceed 65,536 bytes.

Numeric multiplication is unaffected. These guards prevent contracts from allocating large in-memory objects while keeping validation deterministic.

Allowed Export Signature Annotations

The same allowlist applies to exported arguments and exported return annotations:

python
str, int, float, bool, bytes, bytearray, dict, list, set, frozenset, Any
datetime.datetime, datetime.timedelta

In Xian, float in an export signature means a deterministic decimal-backed value at runtime. Use float for user-facing decimal amounts, not Python Decimal.

Examples:

python
@export
def balance_of(address: str) -> float:
    return balances[address]

@export
def decode_batch(items: list[int]) -> dict[str, int]:
    return {
        "count": len(items),
    }

Subscripted container annotations are valid when the base type is allowed, for example list[int] and dict[str, int].

Export Decorator Options

@export may be used in either of these forms:

python
@export
def balance_of(address: str) -> float:
    return balances[address]

@export(typecheck=True)
def transfer(to: str, amount: float):
    balances[ctx.caller] -= amount
    balances[to] += amount

No positional decorator arguments are allowed. The only supported keyword is typecheck, and it must be True or False.

Invalid annotations still fail:

python
@export
def bad(value: Decimal):
    return value

Import Rules

Allowed imports are deployed contracts, for example import currency.

Runtime-provided modules such as hashlib, datetime, random, importlib, crypto, zk, and decimal are injected directly into contract scope and do not need import statements.

The Python standard library is not generally available to contracts beyond that runtime surface.

Practical Guidance

When in doubt:

  • keep contract code flat and explicit
  • keep one statement per line
  • use assert instead of exception handling
  • keep all imports at module scope
  • prefer simple data structures
  • test the contract locally with ContractingClient