ARC-32: Application Specification
A specification for fully describing an Application, useful for Application clients.
Author | Benjamin Guidarelli |
---|---|
Discussions-To | https://github.com/algorandfoundation/ARCs/issues/150 |
Status | Draft |
Type | Standards Track |
Category | ARC |
Created | 2022-12-01 |
Requires | 4 , 21 |
Table of Contents
Abstract
An Application is partially defined by it’s methods but further information about the Application should be available. Other descriptive elements of an application may include it’s State Schema, the original TEAL source programs, default method arguments, and custom data types. This specification defines the descriptive elements of an Application that should be available to clients to provide useful information for an Application Client.
Motivation
As more complex Applications are created and deployed, some consistent way to specify the details of the application and how to interact with it becomes more important. A specification to allow a consistent and complete definition of an application will help developers attempting to integrate an application they’ve never worked with before.
Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 822..
Definitions
- Application Specification: The object containing the elements describing the Application.
- Source Specification: The object containing a description of the TEAL source programs that are evaluated when this Application is called.
- Schema Specification: The object containing a description of the schema required by the Application.
- Type Specification: The object containing a map type name of name to the user defined data types
- Error Specification: The object containing a map of
pc
to Error message
Application Specification
The Application Specification is composed of a number of elements that serve to fully describe the Application.
type AppSpec = {
// embedded contract fields, see ARC-0004 for more
ABIContract;
// the original teal source, containing annotations, base64 encoded
source?: SourceSpec;
// the schema this application requires/provides
schema?: SchemaSpec;
// map of type name=>user defined type
types?: TypeSpec;
// map of pc=>error message
errors?: ErrorSpec;
}
Source Specification
Contains the source TEAL files including comments and other annotations.
// Opject containing the original TEAL source files
type SourceSpec = {
// b64 encoded approval program
approval: string;
// b64 encoded clear state program
clear: string;
}
Schema Specification
TODO: describe diff between Declared/Reserved and motivation for providing both TODO: describe how to decode the type and the value given the decoded type
The schema of an application is critical to know prior to creation since it is immutable after create. It also helps clients of the application understand the data that is available to be queried from off chain. Individual fields can be referenced from the default argument to provide input data to a given ABI method.
While some fields are possible to know ahead of time, others may be keyed dynamically. In both cases the data type being stored MUST be known and declared ahead of time.
// The complete schema for this application
type SchemaSpec = {
local: Schema;
global: Schema;
}
// Schema fields may be declared explicitly or reserved
type Schema = {
declared: Record<string, DeclaredSchemaValueSpec>;
reserved: Record<string, ReservedSchemaValueSpec>;
}
// Types supported for encoding/decoding
enum AVMType { uint64, bytes }
// string encoded datatype name defined in arc-4
type ABIType = string;
// Fields that have an explicit key
type DeclaredSchemaValueSpec = {
type: AVMType | ABIType;
key: string;
desc: string;
}
// Fields that have an undetermined key
type ReservedSchemaValueSpec = {
type: AVMType | ABIType;
desc: string;
max_keys: number;
}
Type Specification
TODO: rename userdefinedtype
to something else, user is not a great name for it. custom type?
Each user defined type is specified as either an array of StructElement
s or an ABIType
.
If an array of StructElement
s is provided, the UserDefinedType
is treated as a Tuple with named fields. The ABI encoding is exactly as if an ABI Tuple type defined the same element types in the same order. It is important to encode the struct elements as an array since it preserves the order of fields which is critical to encoding/decoding the data properly.
If a single ABIType is provided, the UserDefinedType
is treated as a Type Alias and can be encoded or decoded as the ABIType
directly.
// Type aliases for readability
type FieldName = string;
type ABIType = string;
// Each field in the struct contains a name and ABI type
type StructElement = [FieldName, ABIType];
// Type aliases for readability
type UserDefinedType = StructElement[] | ABIType;
type UserDefinedTypeName = string;
// A map of type name to either a list of struct fields or a single ABI type
type TypeSpec = Record<UserDefinedTypeName, UserDefinedType>
For example a UserDefinedType
that should provide an array of StructElement
s
Given the PyTeal:
from pyteal import abi
class Thing(abi.NamedTuple):
addr: abi.Field[abi.address]
balance: abi.Field[abi.Uint64]
the equivalent ABI type is (address,uint64)
and an element in the TypeSpec is:
{
// ...
"Thing":[["addr", "address"]["balance","uint64"]],
// ...
}
An example UserDefinedType
that is a simple type alias:
from typing import Literal
from pyteal import abi
HashDigest = abi.StaticBytes[Literal[32]]
Produces the following entry in the TypeSpec
{
// ...
"HashDigest":"bytes[32]",
// ...
}
Error Specification
TODO: number as key will fail in certain places, lets do something else?
The Error specification contains a mapping of PC
(or Program counter
TODO: Link to description) to a human readable string that describes the error condition.
When a node returns a logic eval error, the pc
specified in the error message should be looked up in the ErrorSpec map to find the relevant error message.
// TODO: more complex spec for errors? what else would we want?
type ErrorMsg = string;
type ErrorSpec = Record<number, ErrorMsg>;
To build an error spec, compile the source teal program with its source map, and map the PC
of any assert
or err
opcodes with a comment on the immediately preceding line into the ErrorSpec
map.
ex: the following will produce an entry in the error spec like {..., 10: "// Sorry but 2 is not less than 1", ...}
assuming the PC
of the assert
op is 10.
int 1
int 2
<
// Sorry but 2 is not less than 1
assert
Default Argument
TODO: this should probably be proposed in a separate ARC like the read-only
attr?
type DefaultArgumentSource = "global-state" | "local-state" | "abi-method" | "constant";
export type DefaultArgument = {
// Where to look for the default arg value
source: DefaultArgumentSource;
// extra data to include when looking up the value (key for state, actual data for constant)
data: string | bigint | number;
}
Rationale
The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work, e.g. how the feature is supported in other languages.
Backwards Compatibility
All ARCs that introduce backwards incompatibilities must include a section describing these incompatibilities and their severity. The ARC must explain how the author proposes to deal with these incompatibilities. ARC submissions without a sufficient backwards compatibility treatise may be rejected outright.
Test Cases
Test cases for an implementation are mandatory for ARCs that are affecting consensus changes. If the test suite is too large to reasonably be included inline, then consider adding it as one or more files in ../assets/arc-####/
.
Reference Implementation
An optional section that contains a reference/example implementation that people can use to assist in understanding or implementing this specification. If the implementation is too large to reasonably be included inline, then consider adding it as one or more files in ../assets/arc-####/
.
Security Considerations
All ARCs must contain a section that discusses the security implications/considerations relevant to the proposed change. Include information that might be important for security discussions, surfaces risks and can be used throughout the life cycle of the proposal. E.g. include security-relevant design decisions, concerns, important discussions, implementation-specific guidance and pitfalls, an outline of threats and risks and how they are being addressed. ARC submissions missing the “Security Considerations” section will be rejected. An ARC cannot proceed to status “Final” without a Security Considerations discussion deemed sufficient by the reviewers.
Copyright
Copyright and related rights waived via CCO.
Citation
Please cite this document as:
Benjamin Guidarelli, "ARC-32: Application Specification [DRAFT]," Algorand Requests for Comments, no. 32, December 2022. [Online serial]. Available: https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0032.md.