Transition Semantics
A transition is a named state mutation with parameters, preconditions, and updates. Transitions are the only mechanism by which a Form's state changes. The compiler analyzes each transition to generate proof obligations against every declared invariant. If all obligations are discharged, the transition is proven correct. If any obligation fails, compilation is rejected with a counterexample.
Transition Structure
A transition declaration has four components: a name, a parameter list, zero or more require clauses, and a sequence of state updates. The name becomes the entry point in the compiled WASM module. Parameters are typed by inference from their usage within the transition body.
transition name(param1, param2, ...) { require precondition_1 require precondition_2 -- ... more preconditions ... state_var_1 = new_value state_var_2 += delta map_var[key] -= delta -- ... more updates ... }
The semantics are strictly sequential within a transition body. Require clauses are evaluated first, in declaration order. If any require clause evaluates to false, the transition aborts and the state is unchanged. If all require clauses pass, the updates execute in declaration order. After all updates complete, the post-state must satisfy every invariant.
Formal Semantics
A transition t(p1, ..., pk) defines a partial function from states to states. Given pre-state S and parameter values v1, ..., vk, the transition produces post-state S' according to the following rules.
The sequential application of updates means that later updates see the effects of earlier updates within the same transition. For example, if U1 sets x = 5 and U2 reads x, then U2 sees the value 5. This is important for verification because the compiler must thread the state through each update to compute the final post-state.
Require Clauses
A require clause is a boolean expression that must evaluate to true for the transition to proceed. If the expression evaluates to false, the transition aborts with no state change. Require clauses serve two purposes: they enforce runtime preconditions (access control, balance sufficiency, temporal guards), and they provide assumptions that the verifier uses to discharge proof obligations.
Require as Type Guard
Certain require clauses are necessary for type safety. The expression balance[from] -= amount is only well-typed when balance[from] >= amount, because Nat subtraction requires a non-negativity precondition. The require clause require balance[from] >= amount serves as the type guard that makes the subtraction legal. Without it, the compiler rejects the transition as a type error before verification even begins.
Require as Proof Assumption
During verification, the compiler assumes all require clauses hold when proving invariants. The proof obligation for a (transition, invariant) pair is not "the invariant holds in S'" unconditionally, but rather "if all require clauses hold in S and the invariant holds in S, then the invariant holds in S'." This conditional structure means that require clauses can provide facts that the verifier needs to complete a proof.
Update Statements
Update statements modify the Form's state. The Form language supports five update forms.
The send statement is the only mechanism for transferring value out of the contract. It is a side effect, not a state update. The compiler treats send as opaque for verification purposes: it does not affect the Form's state variables. The verifier reasons only about the Form's internal state; the correctness of the external transfer is the responsibility of the target chain's runtime.
Proof Obligation Generation
The compiler generates one proof obligation for every (transition, invariant) pair. A Form with n transitions and m invariants produces n * m proof obligations. Each obligation has the following structure.
The formula reads: if the invariant holds in the pre-state and all require clauses hold, then the invariant holds in the post-state. This is the standard inductive invariant proof structure. The base case (invariant holds in the initial state) is checked separately during Form initialization.
Token Transfer: Complete Proof Obligation Generation
The following derivation shows the complete proof obligation generation for the Token form's transfer transition against the conservation invariant.
transition transfer(from, to, amount) { require balance[from] >= amount -- R1 balance[from] -= amount -- U1 balance[to] += amount -- U2 } invariant conservation : sum(balance) == supply
Token Mint: Complete Proof Obligation Generation
transition mint(to, amount) { require msg.sender == owner -- R1 balance[to] += amount -- U1 supply += amount -- U2 }
Token Burn: Complete Proof Obligation Generation
transition burn(from, amount) { require balance[from] >= amount -- R1 balance[from] -= amount -- U1 supply -= amount -- U2 }
Transition Atomicity
All updates within a transition execute atomically. Either all updates succeed and the post-state satisfies all invariants, or the transition aborts and the state is unchanged. There is no intermediate state visible to other transitions. This atomicity guarantee is essential for invariant preservation: the verifier reasons about the complete pre-state to post-state transformation, never about partial updates.
At the WASM level, atomicity is implemented by the target chain's transaction model. If a require clause fails or the WASM execution traps, the entire transaction is rolled back by the chain runtime. The Form compiler does not emit explicit rollback code; it relies on the host environment's transactional guarantees.
Parameter Typing
Transition parameters are not explicitly typed in the Form language. Their types are inferred from usage within the transition body. If amount appears in balance[from] -= amount where balance : Nat per Address, then amount : Nat. If from appears as a map key in balance[from] where balance : Map(Address, Nat), then from : Address.
If the compiler cannot infer a unique type for a parameter (e.g., the parameter is unused or used in ambiguous contexts), it rejects the transition with a type ambiguity diagnostic.