FireFly Interface Format¶
FireFly defines a common, blockchain agnostic way to describe smart contracts. This is referred to as a Contract Interface, and it is written in the FireFly Interface (FFI) format. It is a simple JSON document that has a name, a namespace, a version, a list of methods, and a list of events.
Overview¶
There are four required fields when broadcasting a contract interface in FireFly: a name
, a version
, a list of methods
, and a list of events
. A namespace
field will also be filled in automatically based on the URL path parameter. Here is an example of the structure of the required fields:
NOTE: Contract interfaces are scoped to a namespace. Within a namespace each contract interface must have a unique name and version combination. The same name and version combination can exist in different namespaces simultaneously.
Method¶
Let's look at a what goes inside the methods
array now. It is also a JSON object that has a name
, a list of params
which are the arguments the function will take and a list of returns
which are the return values of the function. It also has an optional description
which can be helpful in OpenAPI Spec generation. Finally, it has an optional details
object which wraps blockchain specific information about this method. This can be used by the blockchain plugin when invoking this function, and it is also used in documentation generation.
{
"name": "add",
"description": "Add two numbers together",
"params": [],
"returns": [],
"details": {}
}
Event¶
What goes into the events
array is very similar. It is also a JSON object that has a name
and a list of params
. The difference is that events
don't have returns
. Arguments that are passed to the event when it is emitted are in params
. It also has an optional description
which can be helpful in OpenAPI Spec generation. Finally, it has an optional details
object which wraps blockchain specific information about this event. This can be used by the blockchain plugin when invoking this function, and it is also used in documentation generation.
{
"name": "added",
"description": "An event that occurs when numbers have been added",
"params": [],
"details": {}
}
Param¶
Both methods
, and events
have lists of params
or returns
, and the type of JSON object that goes in each of these arrays is the same. It is simply a JSON object with a name
and a schema
. There is also an optional details
field that is passed to the blockchain plugin for blockchain specific requirements.
Schema¶
The param schema
is an important field which tells FireFly the type information about this particular field. This is used in several different places, such as OpenAPI Spec generation, API request validation, and blockchain request preparation.
The schema
field accepts JSON Schema (version 2020-12) with several additional requirements:
- A
type
field is always mandatory - The list of valid types is:
boolean
integer
string
object
array
- Blockchain plugins can add their own specific requirements to this list of validation rules
NOTE: Floats or decimals are not currently accepted because certain underlying blockchains (e.g. Ethereum) only allow integers
The type field here is the JSON input type when making a request to FireFly to invoke or query a smart contract. This type can be different from the actual blockchain type, usually specified in the details
field, if there is a compatible type mapping between the two.
Schema details¶
The details field is quite important in some cases. Because the details
field is passed to the blockchain plugin, it is used to encapsulate blockchain specific type information about a particular field. Additionally, because each blockchain plugin can add rules to the list of schema requirements above, a blockchain plugin can enforce that certain fields are always present within the details
field.
For example, the Ethereum plugin always needs to know what Solidity type the field is. It also defines several optional fields. A full Ethereum details field may look like:
Automated generation of FireFly Interfaces¶
A convenience endpoint exists on the API to facilitate converting from native blockchain interface formats such as an Ethereum ABI to the FireFly Interface format. For details, please see the API documentation for the contract interface generation endpoint.
For an example of using this endpoint with a specific Ethereum contract, please see the Tutorial to Work with custom smart contracts.
Full Example¶
Putting it all together, here is a full example of the FireFly Interface format with all the fields filled in:
{
"namespace": "default",
"name": "SimpleStorage",
"description": "A simple smart contract that stores and retrieves an integer on-chain",
"version": "v1.0.0",
"methods": [
{
"name": "get",
"description": "Retrieve the value of the stored integer",
"params": [],
"returns": [
{
"name": "output",
"schema": {
"type": "integer",
"details": {
"type": "uint256",
"internalType": "uint256"
}
}
}
],
"details": {
"stateMutability": "viewable"
}
},
{
"name": "set",
"description": "Set the stored value on-chain",
"params": [
{
"name": "newValue",
"schema": {
"type": "integer",
"details": {
"type": "uint256",
"internalType": "uint256"
}
}
}
],
"returns": [],
"details": {
"stateMutability": "payable"
}
}
],
"events": [
{
"name": "Changed",
"description": "An event that is fired when the stored integer value changes",
"params": [
{
"name": "from",
"schema": {
"type": "string",
"details": {
"type": "address",
"internalType": "address",
"indexed": true
}
}
},
{
"name": "value",
"schema": {
"type": "integer",
"details": {
"type": "uint256",
"internalType": "uint256"
}
}
}
],
"details": {}
}
]
}