Representable Contract State
an XML-based canonical view of EVM contract state
XML Namespace and Bindings
This page describes the XML namespace and binding attributes used by contracts that implement
IXMLRepresentableState (and the optional IXMLRepresentableStatePart interface).
It is the detailed companion to the concept/spec page.
Namespace
This standard defines a dedicated XML namespace for EVM-state bindings:
- Namespace URI:
urn:evm:state:1.0 - Recommended prefix:
evmstate
A typical root element in a template looks like:
<Contract xmlns="urn:example:instrument"
xmlns:evmstate="urn:evm:state:1.0">
...
</Contract>
All attributes in this namespace (evmstate:*) are processing instructions for an off-chain renderer. The final rendered XML representation may keep or strip these attributes, depending on the use-case.
An element that carries one or more evmstate:* attributes is called a binding element.
Function bindings
Function bindings connect XML elements to contract view functions. A binding describes how to call a function and how to decode the result.
There are two equivalent styles:
- Signature form (preferred) - human-readable and self-describing.
- Selector form (low-level) - uses ABI selectors and explicit return types.
Signature form (preferred)
<Notional
evmstate:call="notional()(uint256)"
evmstate:format="decimal" />
evmstate:callcontains a Solidity function signature string of the form
functionName(inputTypes...)(outputTypes...), without spaces.- The renderer MUST:
- compute the function selector as
keccak256("notional()")[0:4]; - use the declared output type to decode the return data (see below for supported output types).
- compute the function selector as
The signature form is usually easier to read and maintain.
Selector form (low-level)
<Notional
evmstate:selector="0x70a08231"
evmstate:returns="uint256"
evmstate:format="decimal" />
evmstate:selectoris a 4‑byte hex selector as a string with0xprefix.evmstate:returnsis an ABI type string describing the return type (see below for supported return types).
The renderer MUST call the contract using the given selector and decode using the specified type.
Preference and errors
- If both
evmstate:callandevmstate:selectorare present for a single binding, the renderer MUST preferevmstate:calland MAY treat the presence ofselectoras an error.
Target location (single binding)
A single binding can write either to the element’s text content or to one of its attributes.
Text content (default)
If no explicit target is given, the renderer writes the value into the element’s text content:
<Notional
evmstate:call="notional()(uint256)"
evmstate:format="decimal"
evmstate:scale="2" />
becomes, for example:
<Notional>1000000.00</Notional>
Attribute target
If evmstate:target is present and non‑empty, its value is interpreted as the local name of an attribute to populate on the same element:
<Party
evmstate:call="partyALEI()(string)"
evmstate:target="id" />
might render as:
<Party id="TESTPNM19D40DI1WT772" />
(if the string TESTPNM19D40DI1WT772 is the return value of the view partyALEI()).
Rules:
- The renderer MUST create or overwrite an attribute with the given name.
- The renderer MUST NOT modify the element’s text content because of this binding.
- Bindings are always attached to elements, not attributes (XML attributes cannot carry attributes of their own).
Multiple bindings per element
Sometimes a single XML element should aggregate several values, for example an amount as text plus a currency attribute. For this, the binding schema supports both:
- Single‑binding mode, using the singular attributes, and
- Multi‑binding mode, using plural attributes with semicolon‑separated lists.
Single‑binding mode
Only the singular attributes are present:
evmstate:callevmstate:selectorevmstate:returnsevmstate:formatevmstate:scaleevmstate:target
The element describes exactly one binding.
Multi‑binding mode (semicolon‑separated lists)
When any of the plural attributes are present, the element is in multi‑binding mode:
evmstate:callsevmstate:selectorsevmstate:returnsListevmstate:formatsevmstate:scalesevmstate:targets
Each of these attributes is interpreted as a semicolon‑separated list. The lists are interpreted positionally.
Example:
<Amount
evmstate:calls="notional()(uint256);currency()(string)"
evmstate:formats="decimal;string"
evmstate:scales="2; "
evmstate:targets="; currency" />
Semantics:
- Split each plural attribute at
';'. - Trim whitespace around each entry.
- Let
Nbe the length of thecallslist. - For index
i = 0..N-1:calls[i]is the i‑th function signature (optional).selectors[i]is the i‑th selector (optional).returnsList[i]is the i‑th return type (optional).formats[i]is the i‑th format specifier (optional).scales[i]is the i‑th decimal scale (optional).targets[i]is the i‑th target specifier (optional).
Missing list entries are treated as empty strings. If both calls[i] and selectors[i] are empty,
that index is ignored.
For each binding index i:
- If
targets[i]is empty or missing → write to the element’s text content. If several bindings write text, later bindings overwrite earlier ones. - If
targets[i]is non‑empty → write to the attribute with that name. Text content MUST NOT be changed for that binding.
Example: text + attribute
The example above:
<Amount
evmstate:calls="notional()(uint256);currency()(string)"
evmstate:formats="decimal;string"
evmstate:scales="2; "
evmstate:targets="; currency" />
MUST render to something equivalent to:
<Amount currency="EUR">1000000.00</Amount>
Arrays and multi‑binding mode
For the optional array binding profile, array‑valued output types MUST NOT be used in multi‑binding mode. A renderer that implements the array profile MUST treat a multi‑binding with an array return type as an error.
Arrays are handled exclusively by:
- a single binding on the array container, plus
- item‑field bindings inside a template row (see below).
Formatting
The optional attributes evmstate:format / evmstate:scale (or their plural forms in
multi‑binding mode) describe how to render decoded ABI values as strings.
If format is absent or empty, a type‑specific default is used. If scale is absent or empty,
it defaults to 0.
Integer formatting and scaling
For uint* and int* types, implementations MUST support at least:
- Default → same as
"decimal". "decimal"→ base‑10 representation, optionally with scaling."hex"→ lower‑case hex with0xprefix."iso8601-date"→ interpret the integer as a UNIX timestamp in seconds since epoch and render a UTC calendar dateYYYY-MM-DD."iso8601-datetime"→ interpret the integer as a UNIX timestamp in seconds and render a UTC timestamp such as2025-01-02T00:00:00Z.
Scaling is controlled via evmstate:scale:
<Amount
evmstate:call="notional()(uint256)"
evmstate:format="decimal"
evmstate:scale="2" />
Here the raw integer is scaled by 10^(-2). For example, 12345 becomes "123.45".
Address
For address:
- Default format is
"address". "address"→ hex with0xprefix and an [ERC‑55] checksum.
Boolean
For bool:
- Default format is
"boolean". "boolean"→"true"or"false".
Bytes and fixed‑size bytes
For bytes and bytesN:
- Default is
"hex". "hex"→ hex with0xprefix."base64"→ Base64 representation.
String
For string:
- Default is
"string". "string"→ UTF‑8 text as returned.
Unknown formats
Implementations MAY support additional formats. If the renderer encounters an unknown
evmstate:format, it SHOULD treat this as an error.
In multi‑binding mode, evmstate:formats and evmstate:scales provide per‑binding values:
formats[i]applies to the i‑th binding.scales[i]applies to the i‑th binding; empty entries mean scale0.
Array binding profile (optional)
The array binding profile is an optional extension that lets array‑valued bindings render as a sequence of repeated child elements. It is designed to play nicely with XSD and XSLT.
Renderers MAY implement this profile. If they do, they MUST follow the rules in this section. If they do not implement it, they MUST treat any use of the array‑specific attributes (evmstate:item-element, evmstate:item-field) as an error.
Conceptual recursive view of arrays and structures
It is often useful to think about arrays and structs/tuples as if the contract had additional “virtual” element accessors. This is a conceptual model only - these accessors do not have to exist on-chain. The renderer internally performs an equivalent rewrite to scalar bindings.
Arrays
Assume a view function returning an array of some type A:
function arrayView() external view returns (A[] memory);
and a template element
<ArrayElement
evmstate:call="arrayView()(A[])"
evmstate:item-element=""
evmstate:format="..." />
The presence of an empty evmstate:item-element means:
- conceptually, there exists a virtual accessor
arrayElement(uint256 index) returns (A)
that is never implemented on-chain; and - the template above is equivalent to:
<ArrayElement evmstate:call="arrayElement(0)(A)" evmstate:format="..." />
<ArrayElement evmstate:call="arrayElement(1)(A)" evmstate:format="..." />
<ArrayElement evmstate:call="arrayElement(2)(A)" evmstate:format="..." />
...
In the renderer, this is realised by:
- Calling
arrayView()once to obtain the fullA[]. - Repeating the element once per index and feeding
A[i]into each clone.
No arrayElement(uint256) function is ever called on the contract.
If a non-empty item element is present, e.g.
<Array evmstate:call="arrayView()(A[])" evmstate:item-element="Item">
<Item evmstate:format="...">
...
</Item>
</Array>
this is conceptually equivalent to
<Array>
<Item evmstate:call="arrayView()(A[])" evmstate:item-element="" evmstate:format="...">
...
</Item>
</Array>
which then expands as above into multiple Item rows. The formal semantics for this are given in the
following subsections.
Structures / tuples
For a function that returns a tuple (or struct) such as
function method() external view returns (T1, T2, T3);
one may conceptually imagine separate component accessors
methodT1() external view returns (T1);
methodT2() external view returns (T2);
methodT3() external view returns (T3);
and a template
<Structure evmstate:call="method()(T1,T2,T3)" evmstate:targets=";attr2;attr3" />
as equivalent to
<Structure
evmstate:calls="methodT1()(T1);methodT2()(T2);methodT3()(T3)"
evmstate:targets=";attr2;attr3" />
In practice, the renderer calls method() once, decodes the tuple (T1,T2,T3) into its components,
and then distributes them according to targets. Direct tuple bindings in non-array contexts are a
possible future extension; the current reference implementation only uses tuples as array elements in
the array binding profile.
Multiple arrays and “zipped” rows (future extension)
The same mental model extends naturally to several array-valued bindings that are “zipped” into rows. For example:
<Array>
<Item
evmstate:calls="arrayView1()(A[]);arrayView2()(B[])"
evmstate:item-element=""
evmstate:targets=";attr"
evmstate:formats="..." />
</Array>
can be conceptually understood as if there were virtual element accessors
arrayElement1(uint256 i) returns (A);
arrayElement2(uint256 i) returns (B);
and the template was equivalent to:
<Array>
<Item evmstate:calls="arrayElement1(0)(A);arrayElement2(0)(B)" evmstate:targets=";attr" evmstate:formats="..." />
<Item evmstate:calls="arrayElement1(1)(A);arrayElement2(1)(B)" evmstate:targets=";attr" evmstate:formats="..." />
...
</Array>
An implementation would call both arrays once, zip them in memory, and apply the multi-binding per row. This pattern is not part of the 1.0 array binding profile and is not implemented by the reference renderer yet. It is documented here as a natural future extension.
Supported array types
The profile supports bindings whose declared output type is one of:
T[]orT[M], whereTis any scalar ABI type supported by the core profile.tuple(T0,...,Tn-1)[]ortuple(T0,...,Tn-1)[M], where eachTiis a scalar ABI type (e.g.int256,uint256,address,bool,string,bytes,bytesN).
Nested arrays such as uint256[][] or tuple(uint256[],uint256)[] are out of scope and MUST be treated as an error in the current 1.0 profile.
Array containers and evmstate:item-element
An XML element E is an array container if:
- It is in single‑binding mode and has a binding via
evmstate:callorevmstate:selector/evmstate:returns. - The declared output type of that binding is an array type supported by this profile.
- It has an attribute
evmstate:item-element="N", whereNis a non‑empty XML local name.
Within E, the renderer MUST locate the template row as follows:
- Among the direct children of
E, find the first element whose local name is exactlyN. - If such an element exists, it is the template row
T*. - If not, the renderer SHOULD treat this as an error.
Before inserting any rendered rows, the renderer MUST remove the template row T* from the document. If rendering produces zero rows, E will simply have no such child elements.
evmstate:item-element is only meaningful on array containers and SHOULD NOT be used elsewhere.
Evaluation semantics
Given chain‑id C, contract address A, block‑number B, and an array container E:
-
Evaluate the array‑valued binding of
Eat blockB(using the standard function binding rules), producing a sequenceitems[0..N-1].- If the element type is scalar
T, thenitems[i]is a scalar. - If the element type is
tuple(T0,...,Tn-1), thenitems[i] = (v0,...,v{n-1}).
- If the element type is scalar
-
For each index
i = 0..N-1:- Deep‑clone the template row
T*(including descendants and attributes) to produceR. - Within
Rand its descendants, process anyevmstate:item-fieldattributes usingitems[i]as the current row value. - Insert
Ras a child ofE, after any previously inserted rows.
- Deep‑clone the template row
-
If
N = 0,T*is removed and no rows are inserted.
Array‑valued bindings MUST NOT appear in multi‑binding mode in this profile.
evmstate:item-field inside template rows
Inside the subtree rooted at the template row T*, elements MAY carry:
evmstate:item-field="k"
where k is a non‑negative integer index into the array element (not into the array itself).
Let the array element type be:
- scalar
T(e.g.uint256[]), or - tuple
tuple(T0,...,Tn-1)(e.g.tuple(int256,uint256)[]).
For a given row index i and an element X with evmstate:item-field="k":
- Let
value = items[i]. - Determine the selected component
v:- For scalar
T: treatvalueas a tuple(v0)of length 1. The only valid index isk = 0; other values MUST be treated as an error. - For tuple types:
value = (v0,...,v{n-1}). Valid indices are0 <= k < n, andv = vk. Other values MUST be treated as an error.
- For scalar
- Render
vto a string usingX’sevmstate:format/evmstate:scale(or type defaults). - Place the rendered value:
- If
Xhasevmstate:target="attrName", set or overwrite an attributeattrNameonXwith that value; do not change text. - Otherwise, replace the text content of
X.
- If
Restrictions:
evmstate:item-fieldis only meaningful inside the subtree of a template row in an array container.- Within an element that carries
evmstate:item-field, only single‑binding mode is allowed. It MUST NOT be combined with the multi‑binding attributes.
Example: scalar array
Assume a contract function
function couponAmounts() external view returns (int256[] memory);
A template that renders each coupon in its own element:
<Coupons
xmlns:evmstate="urn:evm:state:1.0"
evmstate:call="couponAmounts()(int256[])"
evmstate:item-element="Coupon">
<!-- Template row, cloned once per array element -->
<Coupon
evmstate:item-field="0"
evmstate:format="decimal"
evmstate:scale="2" />
</Coupons>
If the function returns three entries, the rendered XML might be:
<Coupons>
<Coupon>1000000.00</Coupon>
<Coupon>1000000.00</Coupon>
<Coupon>1000000.00</Coupon>
</Coupons>
Example: array of tuples (payment schedule)
Assume
struct Cashflow {
int256 amount; // 18-decimal
uint256 payDate; // unix timestamp
}
function cashflows() external view returns (Cashflow[] memory);
ABI return type: tuple(int256,uint256)[].
A template that renders a payment schedule:
<PaymentSchedule
xmlns:evmstate="urn:evm:state:1.0"
evmstate:call="cashflows()(tuple(int256,uint256)[])"
evmstate:item-element="Payment">
<!-- Template row, cloned once per cashflow -->
<Payment>
<PaymentDate
evmstate:item-field="1"
evmstate:format="iso8601-date" />
<Amount
evmstate:item-field="0"
evmstate:format="decimal"
evmstate:scale="2" />
</Payment>
</PaymentSchedule>
which might render as:
<PaymentSchedule>
<Payment>
<PaymentDate>2026-01-02</PaymentDate>
<Amount>1000000.00</Amount>
</Payment>
<Payment>
<PaymentDate>2026-04-02</PaymentDate>
<Amount>1000000.00</Amount>
</Payment>
<!-- ... -->
</PaymentSchedule>
### Example: array of tuples (settlement history)
Assume
```solidity
struct Settlement {
uint256 time; // unix timestamp
int256 value; // scale 2
}
function settlementHistory() external view returns (Settlement[] memory);
ABI return type: tuple(uint256,int256)[].
A template that renders the settlement history:
<History
xmlns:evmstate="urn:evm:state:1.0"
evmstate:call="settlementHistory()(tuple(uint256,int256)[])"
evmstate:item-element="Settlement">
<!-- Template row, cloned once per settlement -->
<Settlement>
<time
evmstate:item-field="0"
evmstate:format="iso8601-datetime" />
<value
evmstate:item-field="1"
evmstate:format="decimal"
evmstate:scale="2" />
</Settlement>
</History>
More complex document shapes (grouped summaries, tables, inline lists, …) can be derived from this repeated‑element representation using standard XML tools such as XSLT.
Context bindings
Required context bindings: chain, contract, block
The XML representation MUST identify the chain, contract, and block it represents. To that end,
this ERC reserves the following attributes in the evmstate namespace on the root element:
evmstate:chain-idevmstate:contract-addressevmstate:block-number
Typical template:
<Contract xmlns="urn:example:instrument"
xmlns:evmstate="urn:evm:state:1.0"
evmstate:chain-id=""
evmstate:contract-address=""
evmstate:block-number="">
...
</Contract>
These attributes are context bindings filled by the renderer, not by explicit function calls:
evmstate:chain-id→ chain ID (e.g. EIP‑155), base‑10 string.evmstate:contract-address→ contract address, checksummed hex.evmstate:block-number→ block number at which the binding evaluation took place, base‑10 string.
Renderers SHOULD use the evmstate:* namespace for these attributes to avoid collisions with
business schemas. They MAY additionally provide non‑namespaced duplicates if downstream tools
require them.
Renderer metadata (optional)
In addition to the required context bindings (evmstate:chain-id, evmstate:contract-address,
evmstate:block-number), renderers MAY add the following informational attributes to the root
element:
evmstate:renderer-id– a stable identifier of the renderer implementation (for example, a library or class name).evmstate:renderer-version– a version string of the renderer implementation (for example, the Maven artifact version or semantic version).evmstate:renderer-url– an optional URL pointing to documentation or a project page for the renderer.
These attributes are purely informational and MUST NOT affect the semantics of the representation. Two XML documents that differ only in these attributes MUST be considered equivalent for the purposes of XML-completeness, state comparison, and integrity checks.
Example root element in a template using renderer metadata:
<Contract xmlns="urn:example:instrument"
xmlns:evmstate="urn:evm:state:1.0"
evmstate:chain-id=""
evmstate:contract-address=""
evmstate:block-number=""
evmstate:renderer-id=""
evmstate:renderer-version=""
evmstate:renderer-url="">
...
</Contract>
XML representation and XML-complete contracts
For a given chain-id C, contract address A, and block-number B, and for a contract that implements
IXMLRepresentableState, the XML representation at (C, A, B) is defined as follows:
- Choose a JSON-RPC provider for chain
C. - Call
eth_getBlockByNumber(or equivalent) to obtain blockBand its number, or use an externally providedB. - Perform all
eth_callinvocations (forstateXmlTemplate()and for all bound functions) withblockTag = B. - Start from the XML template returned by
stateXmlTemplate(). - Resolve all bindings as specified above and insert the resolved values.
- Fill
evmstate:chain-id,evmstate:contract-address, andevmstate:block-numberon the root element. - Optionally remove all
evmstate:*attributes from the document.
A contract is XML-complete if, for every block B at which its code matches this interface,
the following holds:
Given the XML representation at (C, A, B), one can reconstruct all semantically relevant mutable state that influences the contract's future behaviour (up to isomorphism).
This is a semantic property that cannot be enforced by the EVM itself, but it can be audited and
tested. Authors of contracts that claim to implement IXMLRepresentableState SHOULD ensure that:
- Every mutable storage variable that influences behaviour is either:
- directly bound via an
evmstate:call/evmstate:selector, or - deterministically derivable from bound values via a public algorithm.
- directly bound via an
- Adding new mutable state is accompanied by adding corresponding bindings to the template.
In practice, contracts MAY also expose a separate “state descriptor” view function that lists all bound fields, but this is out of scope for the minimal interface.
