Skip to the content.

API Notes

This page describes aspects of the API that may need explanation.

Contract Deployment

NOTE: Angle brackets (< and >) are used to designate variables.

SIMBA has the concept of contract designs, contract artifacts and deployed contracts. In addition, it has the concept of supporting artifacts such as libraries.

Compiling Contracts

The following will assume a solidity contract.

To compile a contract, send an HTTP POST to v2/organisations/<MY_ORG>/contract_designs/ where <MY_ORG> is an organisation you have write access to.

The JSON payload is:

A return status of 200/201 signifies successful compilation.

The return value is a contract design object. This includes generated metadata that is used to create the API as well as compilation information such as the binary contract. The id field is important as it is used to create an artifact from the design.

Creating a Contract Artifact

Using the contract design ID in the id field of the returned design, send an HTTP POST to v2/organisations/%s/contract_artifacts/. The JSON payload is:

A return value of 200/201 signifies success.

The return value is a contract artifact object. This is virtually identical to a design. The id field is important as it is used to deploy the contract.

Deploying a Contract Artifact

Using the contract artifact ID in the id field of the returned artifact, send an HTTP POST to v2/organisations/<MY_ORG>/deployments/. The JSON payload is:

A return status of 200/201 response means all went well.

The return value is a deployment object.

Important fields are:

If the deployment is not in a COMPLETED state, you can wait for the deployment to complete. Poll the /v2/organisations/<MY_ORG>/deployments/<DEPLOYMENT_ID/ endpoint with HTTP GET and wait for the state field to be COMPLETED or FAILED.

If in a COMPLETED state, the deployment’s field primary can be queried. This is a JSON object that contains an address field. This should be populated once the deployment has finished. The primary field deployed_artifact_id contains the ID of the deployed contract. Using this ID, you call inspect the deployed contract object by sending an HTTP GET to /v2/organisations/<MY_ORG>/deployed_contracts/<DEPLOYED_CONTRACT_ID>/.

The contract will be available under the name of the Application it was deployed to, and the api name when deploying. E.g., to send transactions to methods use: /v2/apps/<APP_NAME>/contract/<CONTRACT_API_NAME>/<METHOD_NAME>/

Calling and Querying Contract Methods

Smart contract methods come in two flavours:

As a result, HTTP GET is used for two purposes, depending on the nature of the method and POST can only be used against methods that are not getters.

Calling Methods

When submitting a transaction to a contract method via POST, the payload is dependent on the method parameters. The payload is a JSON object where the keys are the method parameter names and the values are the method parameters. The endpoint is /v2/apps/<APP_NAME>/contract/<CONTRACT_API_NAME>/<METHOD_NAME>/ where <METHOD_NAME> is the name of the contract method being called.

For example, given a function defined as below:

function myFunction (
    address myAddress,
    uint16 myInt
    )
public {
    ...
}

The JSON payload would be as follows:

{
  "myAddress": "0xa508dd875f10c33c52a8abb20e16fc68e981f186",
  "myInt": 12
}

Note that Solidity address types as well as byte arrays are encoded as hex strings.

When calling a getter, the request goes to the chain to get the current state form the contract and return the requested value. The endpoint is the same as for POSTing: /v2/apps/<APP_NAME>/contract/<CONTRACT_API_NAME>/<METHOD_NAME>/. Any parameters are turned into HTTP query parameters. Note this restricts the nature of the values a little, although URL encoded JSON is valid for complex types.

Off Chain Data

The special _bundleHash parameter name is used to determine whether a method has been defined to accept file uploads. This field should not be populated by the client side. Instead, if files are present in the current request and the field is defined on the method, then the files are written to off-chain storage with the JSON manifest being constructed and written out alongside the files. The manifest contains the content hashes of the files along with metadata and timestamp. The content hash of the JSON manifest is then set to be the value of the _bundleHash field. This hash value is then what ends up on the chain in the transaction.

For example, given a function defined as below:

Note that these transactions must be submitted using multipart/form-data rather than application/json in order to upload files.

When the transaction completes, the _bundleHash field will be populated with a hash value. This value can then be used to query for the JSON manifest, the gzipped bundle, or files within the bundle.

function myFunction (
    address myAddress,
    uint16 myInt,
    string memory _bundleHash
    )
public {
    ...
}

The payload would be a multipart message containing myAddress as a string, myInt as a string, as multipart interprets everything as strings, and then file uploads. The _bundleHash field is left blank.

When looking at the inputs of the completed transaction, the _bundleHash field will be populated with the content hash of the JSON manifest, e.g.:

{
  "myAddress": "0xa508dd875f10c33c52a8abb20e16fc68e981f186",
  "myInt": 12,
  "_bundleHash": "7a0e488c12c6fdcc67cbf4fc47b61607034157929cd0842eb23adc1e8f199fdf"
}

This _bundleHash value can then be used to in queries to the bundle endpoint for the contract.

The structure of the manifest is as follows:

{
  "alg": "sha256",
  "digest": "hex",
  "files": [
    {
      "alg": "sha256",
      "digest": "hex",
      "uid": "76a5de1f-2a90-41f3-9a55-40278d3e1f8d.gz",
      "mime": "text/plain",
      "name": "file1.txt",
      "hash": "7a0e488c12c6fdcc67cbf4fc47b61607034157929cd0842eb23adc1e8f199fdf",
      "size": 14
    },
    ...
  ],
  "time": 1607169707
}

To query for the manifest send a GET to

/v2/apps/<APP_NAME>/contract/<CONTRACT_API_NAME>/bundle/<BUNDLE_HASH>/manifest/

To query for a file inside a bundle send a GET to

/v2/apps/<APP_NAME>/contract/<CONTRACT_API_NAME>/bundle/<BUNDLE_HASH>/filename/<FILE_NAME>/

The response with be a binary stream of the file which can be written to memory or file.

To query for a bundle send a GET to

/v2/apps/<APP_NAME>/contract/<CONTRACT_API_NAME>/bundle/<BUNDLE_HASH>/

The response with be a binary stream of the tar.gz which can be written to memory or file.

Querying Transaction Methods

Selecting Fields

Specify fields you would like to be returned in the model using the field query parameter.

Example: ```http request fields=method,inputs,transaction_hash,finalized_on


### Filtering

**Basics**

The basic format for filtering is of the form `?filter[FIELD]=VALUE`, where `FIELD` is the field you'd like to match on,
and `VALUE` is the value you'd like to match,
e.g. - GET `/v2/apps/myapp/contract/mycontract/comments?filter[inputs.post]=1`.

In this case, inputs. specifies that the value to match on is within the inputs list for this transaction/method call.

**Modifiers**

Filters can have modifiers applied. These use dot notation. These allow you to perform more complex filtering.
GET `/v2/apps/myapp/contract/mycontract/comments?filter[inputs.post.gte]=1`
for example, will return comments where post is greater than or equal to (gte) 1.

**Operators**

Different data types have different operators that are applicable to them. The default operator is `exact`.

**Numbers**

* `lt`
* `gt`
* `lte`
* `gte`
* `equals`
* `in` (for arrays of numbers)

**Strings**

* `exact`
* `contains`
* `icontains` (case-insensitive contains)
* `startswith`
* `endswith`
* `in` (for arrays of strings)


**Boolean**

* `is`

**Structs, Arrays, and Complex Objects**

Consider the snippet below. `foo()` accepts an `AddressPerson` object, which is a struct, containing an array of structs.

```solidity
struct Addr{
    string street;
    string town;
}

struct AddressPerson{
    string name;
    uint age;
    Addr[] addrs;
}

function foo(AddressPerson memory person) public {}

The data sent to this method may look like the following:

{
  "person":
  {
    "age":  88,
    "name": "a_name_001",
    "addrs":
    [
      {
        "town":   "Nowheresville",
        "street": "Whatever Road"
      }
    ]
  }
}

In order to query on, for example, the street address, you’d construct a query such as ?filter[inputs.person.addrs.0.street.icontains]=whatever.

This would return all transactions, where the street for the address at index 0 contains the string whatever, using a case insensitive match.

Property Access

As seen in the above query, accessing properties is through dot-notation. So accessing a persons age is just inputs.person.age.

Array Item Access

As also seen in the above query, accessing array indices is through dot notation. Accessing index 1 of the addrs array is inputs.person.addrs.1.

Putting it all together

You want to query for a person with the name “Bob” living on a street with “Whatever” in the name.

?filter[inputs.person.name.exact]=Bob&filter[inputs.person.addrs.0.street.icontains]=whatever

In addition to filtering on the transaction inputs field, the following fields support string comparison operators:

The following fields support numeric/datetime comparison operators:

The following fields support the exact comparison operator on their UUID identifiers: