-
Notifications
You must be signed in to change notification settings - Fork 109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ARC56: Extended App Description #258
base: main
Are you sure you want to change the base?
Changes from all commits
ef5f338
6beb9f9
a18a968
1265709
1b19b76
45a4f6a
96bf578
8c983a1
a4c523e
f6a62f0
358a65b
d9046e1
9a5e445
ef47b89
8e3499b
b02c3c1
2a5eb6f
cebfc7d
e6115f0
fd8fe2a
89a6c0c
35fd3fc
8572596
ac0a9b1
05cd0d5
ab956a7
22372b2
8ee7866
f82a2fa
ad5d033
e540d92
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,374 @@ | ||
--- | ||
arc: 56 | ||
title: Extended App Description | ||
description: Adds information to the ABI JSON description | ||
author: Joe Polny (@joe-p), Rob Moore (@robdmoore) | ||
discussions-to: https://github.com/algorandfoundation/ARCs/issues/258 | ||
status: Draft | ||
type: Standards Track | ||
category: ARC | ||
created: 2023-11-14 | ||
requires: 4, 22, 28 | ||
--- | ||
|
||
## Abstract | ||
|
||
This ARC takes the existing JSON description of a contract as described in [ARC-4](./arc-0004.md) and adds more fields for the purpose of client interaction | ||
|
||
## Motivation | ||
|
||
The data provided by ARC-4 is missing a lot of critical information that clients should know when interacting with an app. This means ARC-4 is insufficient to generate type-safe clients that provide a superior developer experience. | ||
|
||
On the other hand, [ARC-32](./arc-0032.md) provides the vast majority of useful information that can be used to <a href="https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/generate.md#1-typed-clients">generate typed clients</a>, but requires a separate JSON file on top of the ARC-4 json file, which adds extra complexity and cognitive overhead. | ||
|
||
## Specification | ||
|
||
### Contract Interface | ||
|
||
Every application is described via the following interface which is an extension of the `Contract` interface described in [ARC-4](./arc-0004.md). | ||
|
||
```ts | ||
/** Describes the entire contract. This interface is an extension of the interface described in ARC-4 */ | ||
interface Contract { | ||
/** The ARCs used and/or supported by this contract. All contracts implicity support ARC4 and ARC56 */ | ||
arcs: number[]; | ||
/** A user-friendly name for the contract */ | ||
name: string; | ||
/** Optional, user-friendly description for the interface */ | ||
desc?: string; | ||
/** | ||
* Optional object listing the contract instances across different networks | ||
*/ | ||
networks?: { | ||
/** | ||
* The key is the base64 genesis hash of the network, and the value contains | ||
* information about the deployed contract in the network indicated by the | ||
* key. A key containing the human-readable name of the network MAY be | ||
* included, but the corresponding genesis hash key MUST also be defined | ||
*/ | ||
[network: string]: { | ||
/** The app ID of the deployed contract in this network */ | ||
appID: number; | ||
}; | ||
}; | ||
/** Named structs use by the application */ | ||
structs: { [structName: StructName]: StructFields }; | ||
/** All of the methods that the contract implements */ | ||
methods: Method[]; | ||
state: { | ||
/** Defines the values that should be used for GlobalNumUint, GlobalNumByteSlice, LocalNumUint, and LocalNumByteSlice when creating the application */ | ||
schema: { | ||
global: { | ||
ints: number; | ||
bytes: number; | ||
}; | ||
local: { | ||
ints: number; | ||
bytes: number; | ||
}; | ||
}; | ||
/** Mapping of human-readable names to StorageKey objects */ | ||
keys: { | ||
global: { [name: string]: StorageKey }; | ||
local: { [name: string]: StorageKey }; | ||
box: { [name: string]: StorageKey }; | ||
}; | ||
/** Mapping of human-readable names to StorageMap objects */ | ||
maps: { | ||
global: { [name: string]: StorageMap }; | ||
local: { [name: string]: StorageMap }; | ||
box: { [name: string]: StorageMap }; | ||
}; | ||
}; | ||
/** Supported bare actions for the contract. An action is a combination of call/create and an OnComplete */ | ||
bareActions: { | ||
/** OnCompletes this method allows when appID === 0 */ | ||
create: ("NoOp" | "OptIn" | "DeleteApplication")[]; | ||
/** OnCompletes this method allows when appID !== 0 */ | ||
call: ( | ||
| "NoOp" | ||
| "OptIn" | ||
| "CloseOut" | ||
| "ClearState" | ||
| "UpdateApplication" | ||
| "DeleteApplication" | ||
)[]; | ||
}; | ||
/** Information about the TEAL */ | ||
sourceInfo?: SourceInfo[]; | ||
/** The pre-compiled TEAL that may contain template variables. MUST be omitted if included as part of ARC23 */ | ||
source?: { | ||
/** The approval program */ | ||
approval: string; | ||
/** The clear program */ | ||
clear: string; | ||
}; | ||
/** The compiled bytecode for the application. MUST be omitted if included as part of ARC23 */ | ||
byteCode?: { | ||
/** The approval program */ | ||
approval: string; | ||
/** The clear program */ | ||
clear: string; | ||
}; | ||
/** Information used to get the given byteCode and/or PC values in sourceInfo. MUST be given if byteCode or PC values are present */ | ||
compilerInfo?: { | ||
/** The name of the compiler */ | ||
compiler: "algod" | "puya"; | ||
/** Compiler version information */ | ||
compilerVersion: { | ||
major: number; | ||
minor: number; | ||
patch: number; | ||
commit?: string; | ||
}; | ||
}; | ||
/** ARC-28 events that MAY be emitted by this contract */ | ||
events?: Array<Event>; | ||
/** A mapping of template variable names as they appear in the teal (not including TMPL_ prefix) to their respecive types and values (if applicable) */ | ||
templateVariables?: { | ||
[name: string]: { | ||
/** The type of the template variable */ | ||
type: ABIType | AVMBytes | StructName; | ||
/** If given, the the base64 encoded value used for the given app/program */ | ||
value?: string; | ||
}; | ||
}; | ||
/** The scratch variables used during runtime */ | ||
scratchVariables?: { | ||
[name: string]: { | ||
slot: number; | ||
type: ABIType | AVMBytes | StructName; | ||
}; | ||
}; | ||
} | ||
``` | ||
|
||
### Method Interface | ||
|
||
Every method in the contract is described via a `Method` interface. This interface is an extension of the one defined in [ARC-4](./arc-0004.md). | ||
|
||
```ts | ||
/** Describes a method in the contract. This interface is an extension of the interface described in ARC-4 */ | ||
interface Method { | ||
/** The name of the method */ | ||
name: string; | ||
/** Optional, user-friendly description for the method */ | ||
desc?: string; | ||
/** The arguments of the method, in order */ | ||
args: Array<{ | ||
/** The type of the argument */ | ||
type: ABIType; | ||
joe-p marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/** If the type is a struct, the name of the struct */ | ||
struct?: StructName; | ||
/** Optional, user-friendly name for the argument */ | ||
name?: string; | ||
/** Optional, user-friendly description for the argument */ | ||
desc?: string; | ||
/** The default value that clients should use. MUST be base64 encoded bytes */ | ||
defaultValue?: string; | ||
}>; | ||
/** Information about the method's return value */ | ||
returns: { | ||
/** The type of the return value, or "void" to indicate no return value. */ | ||
type: ABIType; | ||
/** If the type is a struct, the name of the struct */ | ||
struct?: StructName; | ||
/** Optional, user-friendly description for the return value */ | ||
desc?: string; | ||
}; | ||
/** an action is a combination of call/create and an OnComplete */ | ||
actions: { | ||
/** OnCompletes this method allows when appID === 0 */ | ||
create: ("NoOp" | "OptIn" | "DeleteApplication")[]; | ||
/** OnCompletes this method allows when appID !== 0 */ | ||
call: ( | ||
| "NoOp" | ||
| "OptIn" | ||
| "CloseOut" | ||
| "ClearState" | ||
| "UpdateApplication" | ||
| "DeleteApplication" | ||
)[]; | ||
}; | ||
/** If this method does not write anything to the ledger (ARC-22) */ | ||
readonly?: boolean; | ||
/** ARC-28 events that MAY be emitted by this method */ | ||
events?: Array<Event>; | ||
/** Information that clients can use when calling the method */ | ||
recommendations?: { | ||
/** The number of inner transactions the caller should cover the fees for */ | ||
innerTransactionCount?: number; | ||
/** Recommended box references to include */ | ||
boxes?: { | ||
/** The app ID for the box */ | ||
app?: number; | ||
/** The base64 encoded box key */ | ||
key: string; | ||
/** The number of bytes being read from the box */ | ||
readBytes: number; | ||
/** The number of bytes being written to the box */ | ||
writeBytes: number; | ||
}; | ||
/** Recommended foreign accounts */ | ||
accounts?: string[]; | ||
/** Recommended foreign apps */ | ||
apps?: number[]; | ||
/** Recommended foreign assets */ | ||
assets?: number[]; | ||
}; | ||
} | ||
``` | ||
|
||
### Event Interface | ||
|
||
[ARC-28](./arc-0028.md) events are described using an extension of the original interface described in the ARC, with the addition of an optional struct field for arguments | ||
|
||
```ts | ||
interface Event { | ||
/** The name of the event */ | ||
name: string; | ||
/** Optional, user-friendly description for the event */ | ||
desc?: string; | ||
/** The arguments of the event, in order */ | ||
args: Array<{ | ||
/** The type of the argument */ | ||
type: ABIType; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this isn't part of ARC-4, maybe in the case of a struct, we can avoid re-specifying it as a tuple here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is not a part of ARC4 but it is a part of ARC28. You could make the argument that ARC28 doesn't have much adoption yet, but I think it's better to keep backwards compatibility with existing ARCs |
||
/** Optional, user-friendly name for the argument */ | ||
name?: string; | ||
/** Optional, user-friendly description for the argument */ | ||
desc?: string; | ||
/** If the type is a struct, the name of the struct */ | ||
struct?: StructName; | ||
}>; | ||
} | ||
``` | ||
|
||
### Type Interfaces | ||
|
||
The types defined in [ARC-4](./arc-0004.md) may not fully described the best way to use the ABI values as intended by the contract developers. These type interfaces are intended to supplement ABI types so clients can interact with the contract as intended. | ||
|
||
```ts | ||
/** An ABI-encoded type */ | ||
type ABIType = string; | ||
|
||
/** The name of a defined struct */ | ||
type StructName = string; | ||
|
||
/** Raw byteslice without the length prefixed that is specified in ARC-4 */ | ||
type AVMBytes = "bytes"; | ||
|
||
/** Mapping of named structs to the ABI type of their fields */ | ||
interface StructFields { | ||
[fieldName: string]: ABIType | StructFields; | ||
} | ||
``` | ||
|
||
### Storage Interfaces | ||
|
||
These interfaces properly describe how app storage is access within the contract | ||
|
||
```ts | ||
/** Describes a single key in app storage */ | ||
interface StorageKey { | ||
/** Description of what this storage key holds */ | ||
desc?: string; | ||
joe-p marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/** The type of the key */ | ||
keyType: ABIType | AVMBytes | StructName; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does StorageKey have keyType? Isn't this for singular, known values? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes but I figured it's still useful to know the type for things like explorers and frontends There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So it's intended to indicate the encoding of |
||
/** The type of the value */ | ||
valueType: ABIType | AVMBytes | StructName; | ||
/** The bytes of the key encoded as base64 */ | ||
key: string; | ||
} | ||
|
||
/** Describes a mapping of key-value pairs in storage */ | ||
interface StorageMap { | ||
/** Description of what the key-value pairs in this mapping hold */ | ||
desc?: string; | ||
/** The type of the keys in the map */ | ||
keyType: ABIType | AVMBytes | StructName; | ||
/** The type of the values in the map */ | ||
valueType: ABIType | AVMBytes | StructName; | ||
/** The prefix of the map, encoded as a utf-8 string */ | ||
prefix?: string; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. I can change to base64 |
||
} | ||
``` | ||
|
||
### SourceInfo Interface | ||
|
||
This interface gives clients more information about the contract's source code. | ||
|
||
```ts | ||
interface SourceInfo { | ||
/** The line of pre-compiled TEAL */ | ||
teal?: number; | ||
/** The program counter offset(s) that correspond to this line of TEAL */ | ||
pc?: Array<number>; | ||
/** A human-readable string that describes the error when the program fails at this given line of TEAL */ | ||
errorMessage?: string; | ||
} | ||
``` | ||
|
||
### Template Variables | ||
|
||
Template variables are variables in the TEAL that should be substitued prior to compilation. Template variables **MUST** be an argument to either `pushint` or `pusbyte` (not the pseudo opcodes `int` or `byte`). Using these opcodes is important to ensure that the program does not add them to the constant blocks. | ||
|
||
#### Examples | ||
|
||
##### Valid | ||
|
||
``` | ||
pushint TMPL_FOO | ||
pushbyte TMPL_BAR | ||
``` | ||
|
||
#### Invalid | ||
|
||
Template variables MUST use `pushint` or `pushbyte` | ||
|
||
``` | ||
int TMPL_FOO | ||
byte TMPL_BYTE | ||
``` | ||
|
||
Template variables MUST be the entire argument | ||
|
||
``` | ||
pushint 123TMPL_FOO | ||
pusbyte 0xdeadTMPL_BAR | ||
``` | ||
|
||
## Rationale | ||
|
||
ARC-32 essentially addresses the same problem, but it requires the generation of two separate JSON files and the ARC-32 JSON file contains the ARC-4 JSON file within it (redundant information). The goal of this ARC is to create one JSON schema that is backwards compatible with ARC-4 clients, but contains the relevant information needed to automatically generate comprehensive client experiences. | ||
|
||
### State | ||
|
||
Describes all of the state that MAY exist in the app and how one should decode values. The schema provides the required schema when creating the app. | ||
|
||
### Named Structs | ||
|
||
It is common for high-level languages to support named structs, which gives names to the indexes of elements in an ABI tuple. The same structs should be useable on the client-side just as they are used in the contract. | ||
|
||
### Action | ||
|
||
This is one of the biggest deviation from ARC-32, but provides a much simpler interface to describe and understand what any given method can do. | ||
|
||
## Backwards Compatibility | ||
|
||
The JSON schema defined in this ARC should be compatible with all ARC-4 clients, provided they don't do any strict schema checking for extraneous fields. | ||
|
||
## Test Cases | ||
|
||
NA | ||
|
||
## Reference Implementation | ||
|
||
TODO | ||
|
||
## Security Considerations | ||
|
||
The type values used in methods **MUST** be correct, because if they were not then the method would not be callable. For state, however, it is possible to have an incorrect type encoding defined. Any significant security concern from this possibility is not immediately evident, but it is worth considering. | ||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CCO</a>. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we make this be the TEAL or the bytecode?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you saying have two properties? One for pre-compiled TEAL and one for compiled bytecode?