Kaspalytics Learn is a work in progress.
Updated: Aug 2, 2026

Template Views & Virtual Elements

Two KCC1 techniques for controlling covenant state — template views that pin part of the state as immutable, and virtual elements that commit to values too large to embed.

The previous page treated state as all-or-nothing: one range, entirely mutable. Real covenants need finer control.

  • Some fields should be permanently fixed — a token’s decimals, an owner set at genesis.
  • Some values are too big to carry in the script at all, or would make every transition pay for bytes it does not touch.

KCC1 answers these with two independent techniques. They are often used together, but they solve different problems.

Template views

A template view selects a contiguous subset of the encoded state as its variable range. Encoded state outside that range is treated as part of the template.

state.start <= view.start
view.start + view.len <= state.start + state.len

view.prefix        = R[0 : view.start]
view.encoded_state = R[view.start : view.start + view.len]
view.suffix        = R[view.start + view.len :]
view.template      = (view.prefix, view.suffix)

Two constraints keep views coherent:

  • The range must be non-empty.
  • It must consist of one or more complete consecutive encoded fields — you cannot cut a field in half or start mid-push.

The view’s template hash is TemplateHash(view.prefix, view.suffix), computed exactly as before. The canonical template from the previous page is simply the view that selects the complete encoded state.

The same program, cut three ways

KCC1’s conformance vector is a ten-byte program with three state fields:

template.prefix  = 51
byte[2] a        = 02aabb
bool    b        = 0101
byte[2] c        = 02ccdd
template.suffix  = 75

R           = 5102aabb010102ccdd75
state.start = 1
state.len   = 8

Three declared views over those identical bytes:

View a, b — view.start = 1, view.len = 5 10 bytes
view.prefix 51
view.encoded_state — a, b 02aabb0101 mutable
view.suffix 02ccdd75 c is now template
TemplateHash = 2e2c28131760a1c0942842f8b54fe686321d0080f5161fa803e27af6a15799a4
View b, c — view.start = 4, view.len = 5 10 bytes
view.prefix 5102aabb a is now template
view.encoded_state — b, c 010102ccdd mutable
view.suffix 75
TemplateHash = 0eb10580bcb608ab9efab6e256d4bac6671d724a72951a058d37b42fa205c1ee
View b — view.start = 4, view.len = 2 10 bytes
view.prefix 5102aabb
view.encoded_state — b only 0101 mutable
view.suffix 02ccdd75
TemplateHash = 7b96ebb8023373bfe7aa81f7db8e0e0d9ce492d2b0382fb5586ac60beea8ed12

Views may overlap and may be nested. Here the first two overlap on the complete encoding of b, and the third is nested inside both.

Different views of the same program generally have different template hashes, because each hash commits to every byte outside its own cut. That is the entire mechanism:

Under a given view, everything outside the selected range is part of the template hash. A continuation authenticated against that hash therefore cannot change those bytes — including state fields outside the view.

So under the b view, fields a and c are frozen. A transition using that view can flip b and nothing else. Changing bytes outside a view’s range requires an independently authorized template.

When to reach for a view

A view is the right tool when a contract has fields with genuinely different lifetimes — a mutable counter alongside an immutable configuration, for example. Rather than re-validating the immutable fields on every transition, you pick a view that excludes them and let the template hash do the work.

Virtual elements

A virtual element is a value represented in the program’s bytecode by a commitment rather than its full encoding. The complete value is supplied as an opening when it is needed.

It has four parts:

PartLives in
the commitment cencoded state
a canonical encoding of the complete value(definition)
an openinginvocation data — witness, not state
a verification rule binding the opening to cthe program

A protocol defining a virtual element must specify all five of: the value type and canonical encoding; the commitment scheme and byte length; the opening encoding and where it appears among the invocation arguments; the verification rule; and how a changed value produces the next commitment.

Two rules are non-negotiable:

  • A covenant must verify an opening before using the complete value.
  • When a transition changes the value, the continuation’s state must contain a commitment to the new value’s canonical encoding.

The hash-committed scheme

KCC1 defines one concrete realization:

payload    = Packed(value)
commitment = Hash(payload)

The state field is byte[32] commitment; the opening is payload. The covenant checks Hash(payload) = commitment, decodes, and for a changed value computes Hash(Packed(next_value)).

Packed concatenates the fixed payloads from the Value ABI in declaration order, without script push opcodes. That is the key difference from encoded state, which includes them. It is valid only when the layout has a statically known packed width, including after recursive record lowering.

A fixed record containing (int -5, bool true) 9 bytes
Packed — int -5 0500000000000080 sign-magnitude, no push opcode
Packed — bool true 01 no push opcode
Packed(value) = 050000000000008001 — 9 bytes, supplied as the opening.
What actually lives in the covenant's state 33 bytes
OP_DATA_32 20
commitment = Hash(payload) 15e006c7c506fb20b6de9573e31bdc47591e937c38f9fcf31cdfabe55d122bda 32 bytes, regardless of the value size
The 9-byte value became a 33-byte state field here — but the size is now constant no matter how large the underlying value grows.

That last caption points at the real trade-off. For a nine-byte record a commitment is worse. Virtual elements pay off when the value is large, or when most transitions never need to look inside it — a transition that does not touch the value never has to carry it.

Combining the two

Template views and virtual elements are independent, and KCC1 is explicit that they compose:

  • A template view selects which encoded state fields may change while preserving a template hash.
  • A virtual element commits to a value that is not stored in the program at all.

Select a view that contains the virtual element’s commitment field, and a continuation using that view can update the commitment while every other program and state byte stays immutable.

This is exactly the shape KCC20 uses. Its extended_state_digest is a commitment to token-specific state that the base transfer treats as opaque and must preserve unchanged — while token-specific entrypoints, working under a different view, may update it.

Next

Leaders & Delegators — how multi-input transitions divide validation work.

References

Kaspalytics strives to provide accurate data - our highest level of effort is given to data validation and maintenance. However, we cannot guarantee 100% accuracy. Data is subject to inaccuracies and change.

Contact | © 2026 Kaspalytics