⚠️ This ARC is not recommended for general use or implementation as it is likely to change.

ARC-32: Application Specification Source

A specification for fully describing an Application, useful for Application clients.

AuthorBenjamin Guidarelli
Discussions-Tohttps://github.com/algorandfoundation/ARCs/issues/150
StatusDraft
TypeStandards Track
CategoryARC
Created2022-12-01
Requires 4 , 21

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 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 StructElements or an ABIType.

If an array of StructElements 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 StructElements

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 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.