The JSON of an ABI is the human-readable representation of the interface of a Sway contract.
Current specVersion
is 1.0
The version above should be updated each time this spec changes and the JSON ABI generator should be updated with the new changes along with an increment in the spec version.
Before describing the format of the JSON ABI, we provide some definitions that will make the JSON ABI spec easier to read.
Given the example below:
struct Foo { x: bool }
struct Bar<T> { y: T }
fn baz(input1: Foo, input2: Bar<u64>); // an ABI function
we define the following expressions:
- type concrete declaration: the declaration or definition of a type which can be generic.
struct Foo { .. }
andstruct Bar<T> { .. }
in the example above are both type declarations. Note that generic types may have multiple type concrete declaration. - type metadata declaration: the declaration or definition of a type which can be generic.
struct Foo { .. }
andstruct Bar<T> { .. }
in the example above are both type declarations. The metadata declaration contains component details about the type. And a single type metadata declaration is generated per type, even for generic types. - type application: the application or use of a type.
Foo
andBar<u64>
infn baz(input1: Foo, input2: Bar<u64>);
in the example above are both applications of the type declarationsstruct Foo { .. }
andstruct Bar<T> { .. }
respectively. - type parameter: a generic parameter used in a type declaration.
T
instruct Bar<T>
in the example above is a type parameter. - type argument: an application of a type parameter used in a type application.
u64
ininput2: Bar<u64>
in the example above is a type argument.
The ABI of a contract is represented as a JSON object containing the following properties:
"specVersion"
: a string representing the version pointing to this document versioning.specVersion
enables the reader of the JSON ABI to find the correct specification for that file, this can be done by comparing it to value in spec version."encodingVersion"
: a string representing the version of theABIEncode
andABIDecode
used in this program."programType"
: a string that can be"script"
,"contract"
,"predicate"
,"library"
. This is used by the SDK to generate types without having to manually specify the program type."concreteTypes"
: an array describing all the type concrete declarations used (or transitively used) in the ABI. Each type concrete declaration is a JSON object that contains the following properties:"type"
: a string representing the type, thesha256
of this string generates theconcreteTypeId
."concreteTypeId"
: a unique string hash based ID. Generated as specified in Hash Based Ids."metadataTypeId"
: the the type metadata declaration ID of this type, if the type metadata has components or is generic, otherwise non existent."typeArguments"
: an array of type concrete declarations hash based IDs of the type parameters of the type, if the type is generic, otherwise non existent.
"typesMetadata"
: an array describing all the type metadata declarations used (or transitively used) in the ABI. Each type metadata declaration is a JSON object that contains the following properties:"type"
: a string representation of the type metadata declaration. The section JSON ABI Format for Each Possible Metadata Type Declaration specifies the format for each possible type."metadataTypeId"
: a unique integer ID."components"
: an array of the components of a given type, if any, otherwise non existent. Each component is a type application represented as a JSON object that contains the following properties:"name"
: the name of the component."typeId"
: the type metadata declaration ID or type concrete declaration hash based ID of the type of the component."typeArguments"
: an array of the type arguments used when applying the type of the component, if the type is generic, otherwise non existent. Each type argument is a type application represented as a JSON object that contains the following properties:"typeId"
: the type metadata declaration ID or type concrete declaration hash based ID of the type of the component."typeArguments"
: an array of the type arguments used when applying the type of the type argument, if the type is generic, otherwise non existent. The format of the elements of this array recursively follows the rules described in this section.
"typeParameters"
: an array of type metadata declaration ID of the type parameters of the type, if the type is generic, otherwise non existent. Each type parameter is a type declaration and is represented as described in Generic Type Parameter.
"functions
": an array describing all the functions in the ABI. Each function is a JSON object that contains the following properties:"name"
: the name of the function"inputs"
: an array of objects that represents the inputs to the function (i.e. its parameters). Each input is a type application represented as a JSON object that contains the following properties:"name"
: the name of the input."concreteTypeId"
: the type concrete declaration hash based ID of the type of the input.
"output"
: the type concrete declaration hash based ID of the type being returned by the function.
"loggedTypes"
: an array describing all instances oflog
orlogd
in the contract's bytecode. Each instance is a JSON object that contains the following properties:"logId"
: a string containing the 64bit hash based decimal ID calculated from the first 8 bytes of thesha256
of a string that represents the type logged as defined in Hash Based Ids. Thelog
andlogd
instructions must set their$rB
register to that ID."loggedType"
: the type concrete declaration hash based ID of the value being logged.
"messagesTypes"
: an array describing all instances ofsmo
in the contract's bytecode. Each instance is a JSON object that contains the following properties:"message_id"
: a unique string ID."messageDataType"
: the type concrete declaration hash based ID of the message data being sent.
"configurables"
: an array describing allconfigurable
variables used in the contract. Eachconfigurable
variable is represented as a JSON object that contains the following properties:"name"
: the name of theconfigurable
variable."configurableType"
: the type concrete declaration hash based ID of the type of theconfigurable
variable."offset"
: the specific offset within the contract's bytecode, in bytes, to the data section entry for theconfigurable
variable.
Note: This JSON should be both human-readable and parsable by the tooling around the FuelVM and the Sway programming language. There is a detailed specification for the binary encoding backing this readable descriptor. The Function Selector Encoding section specifies the encoding for the function being selected to be executed and each of the argument types.
Attribute name | Attribute arguments | Semantics |
---|---|---|
storage |
read and/or write |
Specifies if a function reads or writes to/from storage |
payable |
None | Specifies if a function can accept coins: a function without payable attribute must not accept coins |
test |
None | Specifies if a function is a unit test |
inline |
never or always , but not both |
Specifies if a function should be inlined during code generation |
doc-comment |
String | Documentation comment |
doc |
Not defined yet | Not defined yet |
Below is a simple example showing how the JSON ABI for an example that does not use generic or complex types. We will later go over more complex examples.
abi MyContract {
fn first_function(arg: u64) -> bool;
fn second_function(arg: b256);
}
the JSON representation of this ABI looks like:
{
"concreteTypes": [
{
"type": "u64",
"concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0"
},
{
"type": "b256",
"concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b"
},
{
"type": "bool",
"concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903"
},
{
"type": "()",
"concreteTypeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d"
}
],
"typesMetadata": [],
"functions": [
{
"inputs": [
{
"name": "arg",
"concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0"
}
],
"name": "first_function",
"output": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903"
},
{
"inputs": [
{
"name": "arg",
"concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b"
}
],
"name": "second_function",
"output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d"
}
],
"loggedTypes": []
}
Below is a list of the JSON ABI formats for each possible metadata type declaration:
{
"metadataTypeId": <id>,
"type": "struct <struct_name>",
"components": [
{
"name": "<field1_name>",
"typeId": "<field1_type_id>",
"typeArguments": [
{
"typeId": "<type_arg1_type_id>",
"typeArguments": ...
},
{
"typeId": "<type_arg2_type_id>",
"typeArguments": ...
},
...
]
},
{
"name": "<field2_name>",
"typeId": "<field2_type_id>",
"typeArguments": [
{
"typeId": "<type_arg1_type_id>",
"typeArguments": ...
},
{
"typeId": "<type_arg2_type_id>",
"typeArguments": ...
},
...
]
},
...
],
"typeParameters": [
<type_param1_type_id>,
<type_param2_type_id>,
...
]
}
{
"metadataTypeId": <id>,
"type": "enum <enum_name>",
"components": [
{
"name": "<variant1_name>",
"typeId": "<variant1_type_id>",
"typeArguments": [
{
"typeId": "<type_arg1_type_id>",
"typeArguments": ...
},
{
"typeId": "<type_arg2_type_id>",
"typeArguments": ...
},
...
]
},
{
"name": "<variant2_name>",
"typeId": "<variant2_type_id>",
"typeArguments": [
{
"typeId": "<type_arg1_type_id>",
"typeArguments": ...
},
{
"typeId": "<type_arg2_type_id>",
"typeArguments": ...
},
...
]
},
...
],
"typeParameters": [
<type_param1_type_id>,
<type_param2_type_id>,
...
]
}
{
"metadataTypeId": <id>,
"type": "[_; <n>]",
"components": [
{
"name": "__array_element",
"typeId": "<element_type>",
"typeArguments": ...
}
{
"name": "__array_element",
"typeId": "<element_type_id>",
"typeArguments": [
{
"typeId": "<type_arg1_type_id>",
"typeArguments": ...
},
{
"typeId": "<type_arg2_type_id>",
"typeArguments": ...
},
...
]
},
]
}
<n>
is the size of the array.
{
"metadataTypeId": <id>,
"type": "(_, _, ...)",
"components": [
{
"name": "__tuple_element",
"typeId": "<field1_type_id>",
"typeArguments": [
{
"typeId": "<type_arg1_type_id>",
"typeArguments": ...
},
{
"typeId": "<type_arg2_type_id>",
"typeArguments": ...
},
...
]
},
{
"name": "__tuple_element",
"typeId": "<field2_type_id>",
"typeArguments": [
{
"typeId": "<type_arg1_type_id>",
"typeArguments": ...
},
{
"typeId": "<type_arg2_type_id>",
"typeArguments": ...
},
...
]
},
...
]
}
{
"metadataTypeId": <id>,
"type": "generic <name>"
}
<name>
is the name of the generic parameter as specified in the struct or enum declaration that uses it.
Given the following ABI declaration:
enum MyEnum {
Foo: u64,
Bar: bool,
}
struct MyStruct {
bim: u64,
bam: MyEnum,
}
abi MyContract {
/// this is a doc comment
#[payable, storage(read, write)]
fn complex_function(
arg1: ([str[5]; 3], bool, b256),
arg2: MyStruct,
);
}
its JSON representation would look like:
{
"concreteTypes": [
{
"type": "([str[5]; 3], bool, b256)",
"concreteTypeId": "625531542be70834dd127e771101ac1014111718451bfae996d97abe700c66a5",
"metadataTypeId": 1,
},
{
"type": "[str[5]; 3]",
"concreteTypeId": "40c357685306e593eb4c4154377425853a7387ac5a6962d1d9198081a011d64a",
"metadataTypeId": 2,
},
,
{
"type": "str[5]",
"concreteTypeId": "84877f6e98274b9e4721db68b4c0bdb9e52b8e9572c5bd7811c07a41ced882c7",
},
{
"type": "struct MyStruct",
"concreteTypeId": "392d58c694d2d91f3025f2bccfadacf2a105936f5da881b0899185d49f264522",
"metadataTypeId": 4,
},
{
"type": "u64",
"concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0"
},
{
"type": "b256",
"concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b"
},
{
"type": "bool",
"concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903"
},
{
"type": "()",
"concreteTypeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d"
}
],
"typesMetadata": [
{
"metadataTypeId": 1,
"type": "(_, _, _)",
"components": [
{
"name": "__tuple_element",
"typeId": "2",
},
{
"name": "__tuple_element",
"typeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903",
},
{
"name": "__tuple_element",
"typeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b",
}
]
},
{
"metadataTypeId": 2,
"type": "[_; 3]",
"components": [
{
"name": "__array_element",
"typeId": "84877f6e98274b9e4721db68b4c0bdb9e52b8e9572c5bd7811c07a41ced882c7",
}
]
},
{
"metadataTypeId": 3,
"type": "enum MyEnum",
"components": [
{
"name": "Foo",
"typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0",
},
{
"name": "Bar",
"typeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903",
}
]
},
{
"metadataTypeId": 4,
"type": "struct MyStruct",
"components": [
{
"name": "bim",
"typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0",
},
{
"name": "bam",
"typeId": "3",
}
]
},
],
"functions": [
{
"inputs": [
{
"name": "arg1",
"concreteTypeId": "625531542be70834dd127e771101ac1014111718451bfae996d97abe700c66a5",
},
{
"name": "arg2",
"concreteTypeId": "392d58c694d2d91f3025f2bccfadacf2a105936f5da881b0899185d49f264522"
}
],
"name": "complex_function",
"output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d",
"attributes": [
{
"name": "doc-comment",
"arguments": [" this is a doc comment"]
},
{
"name": "payable",
},
{
"name": "storage",
"arguments": ["read", "write"]
}
]
}
],
"loggedTypes": []
}
Given the following ABI declaration:
enum MyEnum<T, U> {
Foo: T,
Bar: U,
}
struct MyStruct<W> {
bam: MyEnum<W, W>,
}
abi MyContract {
fn complex_function(
arg1: MyStruct<b256>,
);
}
its JSON representation would look like:
{
"concreteTypes": [
{
"type": "struct MyStruct<b256>",
"concreteTypeId": "3ddd5c1768dd7869663dc2f868ea8a8ce68bd6064244dbc4286e2c921c8ce962",
"metadataTypeId": 5,
"typeArguments": [
"7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b"
]
},
{
"type": "b256",
"concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b",
},
{
"type": "()",
"concreteTypeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d",
}
],
"typesMetadata": [
{
"metadataTypeId": 1,
"type": "enum MyEnum",
"components": [
{
"name": "Foo",
"type": 2,
},
{
"name": "Bar",
"type": 3,
}
],
"typeParameters": [2, 3]
},
{
"metadataTypeId": 2,
"type": "generic T",
},
{
"metadataTypeId": 3,
"type": "generic U",
},
{
"metadataTypeId": 4,
"type": "generic W",
},
{
"metadataTypeId": 5,
"type": "struct MyStruct",
"components": [
{
"name": "bam",
"type": 1,
"typeArguments": [
{
"typeId": "4",
},
{
"typeId": "4",
}
]
}
],
"typeParameters": [4]
}
],
"functions": [
{
"inputs": [
{
"name": "arg1",
"concreteTypeId": "3ddd5c1768dd7869663dc2f868ea8a8ce68bd6064244dbc4286e2c921c8ce962"
}
],
"name": "complex_function",
"output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d"
}
],
"loggedTypes": []
}
Given the following contract:
struct MyStruct<W> {
x: W,
}
abi MyContract {
fn logging();
}
...
fn logging() {
log(MyStruct { x: 42 });
log(MyStruct { x: true });
}
its JSON representation would look like:
{
"concreteTypes": [
{
"type": "struct MyStruct<bool>",
"concreteTypeId": "eca2a040ce95fc19b7cd5f75bac530d052484d0b1a49267a2eb07a7a1b00c389",
"metadataTypeId": 1,
"typeArguments": [
"b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903"
]
},
{
"type": "struct MyStruct<u64>",
"concreteTypeId": "b2fa346d9ca66ceca61951a27dba2977b2a82b8aa8600670604f286a1393dffe",
"metadataTypeId": 1,
"typeArguments": [
"1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0"
]
},
{
"type": "bool",
"concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903",
},
{
"type": "u64",
"concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0",
},
{
"type": "()",
"concreteTypeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d",
}
],
"typesMetadata": [
{
"metadataTypeId": 1,
"type": "struct MyStruct",
"components": [
{
"name": "x",
"typeId": "2",
"typeArguments": null
}
],
"typeParameters": [2]
},
{
"metadataTypeId": 2,
"type": "generic W",
},
],
"functions": [
{
"inputs": [],
"name": "logging",
"output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d"
}
],
"loggedTypes": [
{
"logId": "12896678128313068780",
"loggedType": "b2fa346d9ca66ceca61951a27dba2977b2a82b8aa8600670604f286a1393dffe"
},
{
"logId": "16383228984366451899",
"loggedType": "eca2a040ce95fc19b7cd5f75bac530d052484d0b1a49267a2eb07a7a1b00c389"
}
]
}
The logIds
are calculated from:
- First 8 bytes of
sha256("struct MyStruct<u64>")
=> "12896678128313068780" - First 8 bytes of
sha256("struct MyStruct<bool>")
=> "16383228984366451899"