Representable Contract State
an XML-based canonical view of EVM contract state
XML Namespace and Bindings
Namespace
This standard defines the XML namespace URI:
- Namespace URI:
urn:evm:state:1.0 - Recommended prefix:
evmstate
The XML template MUST declare this namespace, for example:
<Contract xmlns="urn:example:instrument"
xmlns:evmstate="urn:evm:state:1.0">
...
</Contract>
Bindings
Bindings are expressed as attributes in the evmstate namespace on XML elements.
A binding element is any XML element that has one or more attributes in the evmstate namespace.
Function binding
To bind an element or attribute to a contract view function, the template uses either:
- Signature form (preferred)
<Notional
evmstate:call="notional()(uint256)"
evmstate:format="decimal" />
evmstate:callis a Solidity function signature string of the form
functionName(inputTypes...)(outputTypes...), with no spaces.- The renderer MUST:
- compute the function selector as
keccak256("notional()")[0:4], and - use the declared output type
(uint256)to decode the return data.
- compute the function selector as
- Selector form (low-level)
<Notional
evmstate:selector="0x70a08231"
evmstate:returns="uint256"
evmstate:format="decimal" />
evmstate:selectoris a 4‑byte hex selector as a string with a0xprefix.evmstate:returnsis an ABI type string describing the return type.- The renderer MUST call the contract using the provided selector and decode using the given type.
If both evmstate:call and evmstate:selector are present, the renderer MUST prefer evmstate:call and MAY treat evmstate:selector as an error.
Core scalar profile vs. arrays
For the core scalar profile, the output type of a binding MUST be a single, non-array ABI type, e.g.
uint256,int256address,bool,stringbytesN,bytes
Implementations MAY additionally support the optional array binding profile (described below), which allows array and array-of-tuple return types to drive repeated XML elements.
An implementation that does not support the array binding profile SHOULD treat any binding whose declared output type is an array (e.g. uint256[], tuple(uint256,uint256)[]) as an error.
Target location (single binding)
A single binding can either target the element's text content or one of its attributes:
- If
evmstate:targetis absent or empty, the renderer MUST replace the element's text content with the rendered value.
Example
<Notional
evmstate:call="notional()(uint256)"
evmstate:format="decimal"
evmstate:scale="2" />
might render to:
<Notional>1000000.00</Notional>
- If
evmstate:targetis present and non-empty, its value is the local name of an attribute to be populated.
Example
<Party
evmstate:call="partyALEI()(string)"
evmstate:target="id" />
might render to:
<Party id="LEI-of-Party-A" />
The renderer MUST create or overwrite the attribute with that name on the element. It MUST NOT change the element's text content in this case.
Bindings MUST NOT be attached directly to attributes (XML does not allow attributes on attributes); all evmstate:* attributes are always attached to elements.
Multiple bindings per element
A single XML element can have one or more bindings associated with it.
To make this explicit, we distinguish:
-
Single-binding attributes (no semicolons, exactly one binding):
evmstate:callevmstate:selectorevmstate:returnsevmstate:formatevmstate:scaleevmstate:target
-
Multi-binding attributes (semicolon-separated lists, interpreted positionally):
evmstate:callsevmstate:selectorsevmstate:returnsListevmstate:formatsevmstate:scalesevmstate:targets
When any of the plural attributes (evmstate:calls, evmstate:selectors, …) are present, the element is in multi-binding mode:
- Each list is split on
';', and each part is trimmed of leading and trailing whitespace. - The lists are interpreted positionally. For index
i:calls[i]is the i‑th function signature (optional).selectors[i]is the i‑th selector (optional).returnsList[i]is the i‑th explicit 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).
Bindings are resolved in order i = 0..N-1, where N is the length of the evmstate:calls list.
If both calls[i] and selectors[i] are empty for a given index, that index MUST be ignored.
If a list is shorter than N, missing entries MUST be treated as empty strings.
For each binding index i, targets[i] determines whether the value is written to the element's text content or to an attribute:
-
If
targets[i]is empty or missing (after trimming), the renderer MUST replace the element's text content with the rendered value for that binding. If multiple bindings for the same element write text, they MUST be applied in index order; later writes overwrite earlier ones. -
If
targets[i]is a non-empty string, the renderer MUST set (create or overwrite) an attribute on the element with that local name and the rendered value as its value. It MUST NOT change the element's text content because of this binding.
When only the singular attributes are present (no evmstate:calls/evmstate:formats/…), the element is in single-binding mode, and the renderer MUST treat evmstate:call / evmstate:selector / evmstate:returns / evmstate:format / evmstate:scale / evmstate:target as describing exactly one binding.
For the optional array binding profile (see below), array-valued return types MUST NOT be used in multi-binding mode. Array handling is restricted to single-binding mode on the array container and to single-binding nodes inside the template row.
Example: single binding to the element's text
<Notional
evmstate:call="notional()(uint256)"
evmstate:format="decimal"
evmstate:scale="2" />
might render to:
<Notional>1000000.00</Notional>
Example: two bindings – notional as element text, currency as attribute
<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>
Formatting
The optional attribute evmstate:format describes how to convert the decoded ABI value into a text string.
If evmstate:format is absent or empty, a type-specific default is used.
When evmstate:formats is used, each entry formats[i] applies to the i‑th binding in multi-binding mode as described above. Similarly, when evmstate:scale or evmstate:scales are present, scale / scales[i] apply to the corresponding binding; a missing or empty entry is treated as scale 0.
Implementations SHOULD support at least the following combinations:
-
For unsigned integers (
uint*) and signed integers (int*):- Default → same as
"decimal". "decimal"→ base‑10 representation, optionally with scaling as described below."hex"→ lower-case hex with0xprefix."iso8601-date"→ interpret the integer as a UNIX timestamp in seconds since epoch and render a UTC calendar date in ISO 8601 formYYYY-MM-DD."iso8601-datetime"→ interpret the integer as a UNIX timestamp in seconds since epoch and render a UTC timestamp in ISO 8601 form (e.g.2025-01-02T00:00:00Z).
- Default → same as
-
For
address:- Default → same as
"address". "address"→ hex with0xprefix and ERC‑55 checksum.
- Default → same as
-
For
bool:- Default → same as
"boolean". "boolean"→"true"or"false".
- Default → same as
-
For
bytesandbytesN:- Default → same as
"hex". "hex"→ hex with0xprefix."base64"→ base64 representation.
- Default → same as
-
For
string:- Default →
"string". "string"→ UTF‑8 text as returned.
- Default →
Implementations MAY support additional formats. If the renderer encounters an unknown evmstate:format, it SHOULD treat this as an error.
Scaling
Optionally, an evmstate:scale / evmstate:scales attribute MAY be used for decimal-like integers:
<Amount
evmstate:call="notional()(uint256)"
evmstate:format="decimal"
evmstate:scale="2" />
This means that the raw integer is scaled by 10^(-scale) before rendering, e.g. 12345 with scale="2" becomes "123.45".
Array binding profile (optional, “Mode B”)
The array binding profile is an optional extension that some renderers may implement.
It allows a single array-valued binding to drive a repeated list of child elements.
Other array-shaped representations (e.g. inline lists, aggregates) are intentionally left to off‑chain post-processing (for example via XSLT) and are not part of this profile.
Supported array output types
The array binding 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.
Nested arrays (e.g. uint256[][], tuple(uint256[],uint256)[]) are out of scope.
A renderer that implements this profile SHOULD treat such types as an error.
Array containers and template rows
An XML element E is an array container if all of the following hold:
- 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.
- The element has an attribute
evmstate:item-elementwhose value is a non-empty XML local name, denotedN.
Within an array container E, the renderer locates the template row as follows:
- It searches among the direct children of
Efor the first element whose local name is exactlyN. - If such a child exists, that element is the template row
T*. - If no such child exists, 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 have no child corresponding to the template.
The evmstate:item-element attribute is only meaningful on array containers and SHOULD NOT be used elsewhere.
Evaluation semantics (informal)
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 normal function-binding rules, yielding a sequenceitems[0..N-1].- If the element type is scalar
T, eachitems[i]is a scalar value. - If the element type is
tuple(T0,...,Tn-1), eachitems[i]is decoded as a tuple(v0,...,v{n-1}).
- If the element type is scalar
-
For each index
ifrom0toN-1:- Deep-clone the template row
T*(including its descendants and attributes) to a new elementR. - Within
Rand its descendants, process anyevmstate:item-fieldattributes as described below, usingitems[i]as the current row value. - Insert
Ras a child ofE, after any previously inserted rows, preserving the original document order of other children ofE.
- Deep-clone the template row
-
If
N = 0, the renderer MUST removeT*and MUST NOT insert any rows derived from it.
Array-valued bindings MUST NOT be used in multi-binding mode (evmstate:calls, evmstate:selectors, etc.) in this profile.
Item-field bindings
Inside the subtree rooted at the template row T*, elements MAY carry an attribute:
evmstate:item-field="k"
where k is a non-negative integer index into the array element.
Let the ABI 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 a node X inside the cloned row R that has evmstate:item-field="k":
-
Determine
value = items[i]. -
Determine the selected component
v:-
If the element type is scalar
T,valueis a single scalar. For this profile, it is treated as a tuple(v0)of length 1. The only valid index isk = 0. Ifk != 0, this SHOULD be treated as an error. -
If the element type is a tuple
tuple(T0,...,Tn-1), thenvalue = (v0,...,v{n-1}). The indexkMUST satisfy0 <= k < n, andv = vk. Otherwise this SHOULD be treated as an error.
-
-
Render
vto a string using the existing scalar formatting rules onX(evmstate:format,evmstate:scale). Ifevmstate:formatis absent onX, the default for the ABI type ofvis used. -
Place the rendered string:
-
If
Xhas an attributeevmstate:target="attrName", the renderer sets (creates or overwrites) an attributeattrNameonXwith the rendered string as its value and MUST NOT changeX’s text content because of this binding. -
If
Xhas noevmstate:targetattribute, the renderer MUST replace the text content ofXwith the rendered string.
-
The evmstate:item-field attribute is only meaningful inside the subtree of a template row in an array container; its use elsewhere SHOULD be treated as an error.
Within a node that carries evmstate:item-field, only single-binding mode is allowed. It MUST NOT be combined with the multi-binding attributes (evmstate:calls, evmstate:selectors, etc.) in this profile.
Example: scalar array
Contract function:
function couponAmounts() external view returns (int256[] memory);
Template:
<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 amounts, 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)
Contract function:
struct Cashflow {
int256 amount; // 18-decimal
uint256 payDate; // unix timestamp
}
function cashflows() external view returns (Cashflow[] memory);
ABI return type is tuple(int256,uint256)[]. Template:
<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>
Rendered XML:
<PaymentSchedule>
<Payment>
<PaymentDate>2026-01-02</PaymentDate>
<Amount>1000000.00</Amount>
</Payment>
<Payment>
<PaymentDate>2026-04-02</PaymentDate>
<Amount>1000000.00</Amount>
</Payment>
<!-- ... -->
</PaymentSchedule>
More complex document shapes (inline lists, grouped summaries, aggregates) can be derived from this repeated-element representation using standard XML transformation tools such as XSLT.
Chain and contract identification
The XML representation MUST identify the chain, contract, and block that it represents.
This standard reserves the following attributes in the evmstate namespace on the root element:
evmstate:chain-idevmstate:contract-addressevmstate:block-number
Example root element in the 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:
- The renderer MUST set
evmstate:chain-idto the EIP‑155 chain ID, as a base‑10 string. - The renderer MUST set
evmstate:contract-addressto the contract address, as a checksummed hex address. - The renderer MUST set
evmstate:block-numberto the block number at which the representation was evaluated, as a base‑10 string.
These fields are filled based on the RPC context (chain id, contract address, and block tag) and do not correspond to actual contract calls.
After rendering, the root element in the final XML might look like:
<Contract xmlns="urn:example:instrument"
xmlns:evmstate="urn:evm:state:1.0"
evmstate:chain-id="1337"
evmstate:contract-address="0x588d26a62d55c18cd6edc7f41ec59fcd4331e227"
evmstate:block-number="37356">
...
</Contract>
The renderer SHOULD set these attributes in the evmstate namespace (e.g. evmstate:chain-id, evmstate:contract-address, evmstate:block-number) to avoid collisions with existing attributes defined by the business XML schema. Implementations MAY additionally provide non-namespaced duplicates if required by downstream tooling.
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.
