Smart Contract APIs

Here we take a detailed look at the APIs provided by the REST API Gateway.

The APIs provide enterprise grade connectivity for your on-chain smart contracts.

  • Friendly and intuitive APIs
    • Generated directly from your Solidity source code and devdocs
    • Simple JSON types
    • Familiar REST semantics
    • OpenAPI 2.0 (Swagger) compliant definitions
    • Built-in UI exerciser
    • Factory APIs to deploy contract instances
    • Instance APIs to query and transact with any on-chain contract
    • Subscription APIs to deliver events reliably to Event Streams
    • Automated Gas estimation
  • Synchronous mode
    • Query on-chain data, returning simple JSON types
    • Simulate transactions
    • Submit transactions with blocking calls (just like web3 APIs)
  • Asynchronous mode
    • Reliably stream transactions onto the chain
    • Pre-built infrastructure that is required for production blockchain workloads at scale
    • Also ideal for webhooks - fire and forget
    • Optimized throughput, smoothing peaks in workload to avoid flooding blocks
    • Nonce management
    • Backed by a fully-managed reliable Kafka messaging backbone
    • Receipt store for transaction results
  • Private transaction support
    • Tessera (previously Constellation) - from the Quorum project
    • Orion (sister project to Hyperledger Besu) - from PegaSys engineering
  • High-performance gateway runtime
    • Written in Golang using optimized Ethereum libraries for ABI packing/unpacking
    • Colocated with the Ethereum node
    • Architected for both horizonal scale and ordered delivery

Gateway APIs

When you teach the API Gateway about the type of a smart contract, you get an API that can talk to any instance of that contract.

Use these when your application might want to interface with many instances of a contract, or the OpenAPI (Swagger) YAML definition or generated API needs to be embedded into the application before the address is known.

The REST API Gateway generates the Gateway API using:

  • The Application Binary Interface (ABI) of the contract, that generated alongside the bytecode during a compile
  • The Developer Docs (devdoc) included in the source code comments in your Solidity
  • The Bytecode itself to allow instances of the contract to be deployed

There are two ways to generate Gateway APIs with all this information:

  • Use the + Connect panel of an individual node and upload the source code for compilation, or POST to compile
    • This is what was shown in the Usage topic
    • Base Path: /abis/:abi_id
    • Only available on the individual node you installed the source code to
  • Use the Smart Contract Management capabilities of Kaleido to promote the interface to all nodes in the environment
    • Base Path: /gateways/:abi_id
    • Short Base Path: /g/:gateway_id
    • Available on all nodes in the environment

Instance APIs

When you use the API Gateway to deploy an instance of a contract onto the blockchain, we generate a new API that is scoped to just that instance of the contract.

Use these APIs for cases where your application interacts with just one instance of the contract.

The methods are the same, but the factory methods of the Gateway API are unavailable so you:

  • Cannot deploy/register new instances of the contract from this API
  • Cannot subscribe for events against all instances

We provide friendly path names that can further abstract the Ethereum hex address of the contract from your application code

API Summary

The generated REST APIs provide paths for all the methods of your smart contract.

  • POST /:method_name performs on-chain transactions, unless kld-call is set or the method is read-only (or view)
  • The body contains the inputs for the transaction
  • GET /:method_name executes logic and return data from the contracts, but never invokes transactions
  • The query parameters contain the inputs for the transaction

Event subscription

Additionally the REST API contains methods to subscribe to events emitted by the contract.

  • POST /:event_name/subscribe creates a subscription

Body for subscribe operations:

Field Description
fromBlock The block from which to start streaming transactions. Omit this field or use latest to start listening from the current block
stream The ID of the Event Stream previously created

API Query Parameters / Headers

The following common query parameters, also available as HTTP headers, are used across the methods to govern behavior of the REST API Gateway when executing the request.

Query Param Header Description
kld-from x-kaleido-from Required: The from address to use to sign the transaction
kld-ethvalue x-kaleido-ethvalue Optional amount of the chain's native "Ether" to send
kld-gas x-kaleido-gas Optional maximum gas to allow for the transaction
kld-gasprice x-kaleido-gasprice Optional gas price to offer with the transaction
kld-sync x-kaleido-sync When set the REST API blocks until the transaction is mined
kld-call x-kaleido-call When set the transaction is read-only, even on POST
kld-privatefrom x-kaleido-privatefrom Tessera / Orion private transactions - from address
kld-privatefor x-kaleido-privatefor Set multiple times to add multiple private-for addresses
kld-register x-kaleido-register Register a Friendly Path Name (constructor only)

Synchronous vs. Asynchronous

If you do not specify kld-sync then the transaction will be delivered asynchronously to the node over our reliable Kafka backed streaming technology.

REST API Gateway

Instead of your REST API call blocking for a number of seconds to wait for the transaction to be mined into a block, you receive a response immediately - once the request has been placed on your private Kafka topic.

Example async confirmation

{
  "sent": true,
  "id": "4696c9f7-2163-4237-7b58-0884fff5fbaf",
  "msg": "u0j6rld2ka-u0uk478rin-requests:0:1"
}

Receipt Store

The receipt is stored for you in a receipt store once the transaction is mined, so it can be queried at a later point.

See Webhooks for details of querying for receipts, and examples of different kinds of receipts

Single-node scoped APIs

When you compile and install contract source code into the REST API Gateway of an individual node (such as through the + Connect panel), the instance APIs of contracts you deploy there are only available on that individual node.

If you are using full Smart Contract Management you can skip this section, as we automatically make the gateway and instance

POST /abis to Compile

This is the API used by the + Connect panel. It compiles the supplied Solidity source code into an ABI (and devdocs) from a single file or zip/tarball, then stores the information locally to the node to serve a new /abis/:abi_id Gateway API.

The primary input is file data, so the Content-Type for the payload on route is multipart/form-data (not JSON).

Parameters

Form field Type Description
findsolidity string Discovery mode: If set then the response will be an array of Solidity files found in the supplied files, rather than attempting the compilation (can also be set as a URL query parameter)
findcontracts string Discovery mode: If set then the response will be an array of contract names returned by solc in the compiled output, rather than attempting to install the REST API (can also be set as a URL query parameter)
compiler string Specify a compiler version to use - only the major part of the version is require such as 0.4 or 0.5
source string If a zip/tarball is supplied containing multiple solidity files, this field is required to set the Solidity source code file to compile (can also be set as a URL query parameter). Use findsolidity to find possible values.
contract string If the compilation results in multiple contracts, this field is required to set the contract name to use when deploying contracts via the factory methods (can also be set as a URL query parameter). Use findcontracts to find possible values.
* file Any other properties should be file-content: .sol .zip .tar .tgz .tar.gz .tar.bz2 files are supported

Apart from the file data, you can use URL query or form parameter for the settings

Example

curl -F file=@simplestorage.sol -F compiler=0.5 -u $USER:$PASS https://MYENV-MYNODE-connect.us0-aws.kaleido.io/abis

You will receive back a JSON payload that contains the path to the new API, available on that node.

{
    "created": "2019-10-05T15:42:30Z",
    "id": "11b5d56c-3fc0-4420-7f27-3f86bdc0ddea",
    "name": "simplestorage",
    "description": "",
    "path": "/abis/11b5d56c-3fc0-4420-7f27-3f86bdc0ddea",
    "deployable": true,
    "openapi": "https://u0j6rld2ka-u0uk478rin-connect.us0-aws.kaleido.io/abis/11b5d56c-3fc0-4420-7f27-3f86bdc0ddea?swagger",
    "compilerVersion": "0.5.4"
}

Then we use it to deploy a new instance of a smart contract

FROM_ADDRESS="0xb863185C6361A226Edc3Ec11EB891a2CfDDc5685"
curl -H 'content-type: application/json' -d '{"value":"12345"}' -u $USER:$PASS "https://u0j6rld2ka-u0uk478rin-connect.us0-aws.kaleido.io/abis/11b5d56c-3fc0-4420-7f27-3f86bdc0ddea?kld-from=$FROM_ADDRESS&kld-sync"
{
  "headers": {
    "id": "d54fa0db-8017-462f-4ecb-10db967d81ca",
    "type": "TransactionSuccess",
    "timeReceived": "2019-10-05T15:53:09.246382449Z",
    "timeElapsed": 6.5209795249999996,
    "requestOffset": "",
    "requestId": "b71bdafe-e8e3-40ba-61ad-2a5f9e8c1817"
  },
  "blockHash": "0x7fb2a0d3de1aa4b01f4484390c2e9ddae7b1b86d0545fd58a253331c7f56082d",
  "blockNumber": "565254",
  "openapi": "https://u0j6rld2ka-u0uk478rin-connect.us0-aws.kaleido.io/contracts/3454c49e14b1ba7453e8780413ba2bd5168feffe?swagger",
  "apiexerciser": "https://u0j6rld2ka-u0uk478rin-connect.us0-aws.kaleido.io/contracts/3454c49e14b1ba7453e8780413ba2bd5168feffe?ui",
  "contractAddress": "0x3454c49e14b1ba7453e8780413ba2bd5168feffe",
  "cumulativeGasUsed": "345490",
  "from": "0xb863185c6361a226edc3ec11eb891a2cfddc5685",
  "gasUsed": "131914",
  "nonce": "0",
  "status": "1",
  "to": null,
  "transactionHash": "0x2fcbf56c2f847a80a7ad839495e80d4281d84d7adfc805badeed779ef537d11f",
  "transactionIndex": "20"
}

Instance API /contracts/:id scoped to one node

When you use this returned Gateway API to deploy instances, the generated instance API will be hosted on a /contracts/:address url.

Register an instance on additional nodes

You can make the same instance API available on multiple nodes, by:

  • Installing the same source code to multiple nodes, using POST on /abis
  • Using POST to /abis/:abi_id/:address on additional nodes to teach them about the instance

This explicit registration process takes many steps to ensure the same API is available on every node, and must be repeated when new nodes join the network. So when you need the same REST API available on multiple nodes, we recommend you use Kaleido's Smart Contract Management capabilities instead of explicit registration.

Smart Contract Management Integration

The Kaleido REST API Gateway is fully integrated with the Smart Contract Management capabilities, so the Gateway and Instance APIs are made available automatically on every node when the contracts are deployed.

Gateway APIs available after promote

When you promote a Compiled Smart Contract to an Environment via a Smart Contract Project at the Consortium level, you will be able to access the Gateway API on every node in the environment automatically.

Promotion teaches an environment about a binary version of a smart contract, and provides the Gateway API on all nodes to deploy instances.

Instance APIs discovered via the Transaction Analyzer

The Kaleido chain indexer performs analysis on every smart contract deployment transaction that occurs on the chain.

When there is a match to a known Compiled Smart Contract, we automatically make an API available for that instance on every node in the environment.

So when you are using Smart Contract Management, we make the instance APIs available to query the the contract data whether you use the Gateway APIs to deploy the contract, or you deploy the contract (with identical bytecode) via an external transaction.

Friendly Path Names

Often it is useful to have a friendly name used in your application code, rather than a Hex Ethereum address, to refer to your on-chain smart contracts. So in Kaleido we allow you to register a name for an instance when you deploy it. Then this name is bound to a path on the API.

If you are using Smart Contract Management this friendly path name will be made available on every node in the environment.

Deploying an Instance with a Friendly Name

In this example we use a Gateway API installed via Smart Contract Management to deploy a new instance of a contract, and register it with the friendly name helloworld

FRIENDLY_NAME="helloworld"
FROM_ADDRESS="0xb863185C6361A226Edc3Ec11EB891a2CfDDc5685"
curl -u $USER:$PASS -H 'content-type: application/json'  -d '{"initVal":"12345"}' "https://zzrtk3l7n1-zzqpc0yvhg-connect.us0-aws.kaleido.io/gateways/zzyko5nodl?kld-reister=$FRIENDLY_NAME&kld-sync&kld-from=$FROM_ADDRESS"

In the result, you can see the instance registered on the /instances/helloworld path.

{
  "headers": {
    "id": "647083fd-8aea-4b6a-70c3-4cdabdac7ccd",
    "type": "TransactionSuccess",
    "ctx": {
      "isRemoteRegistry": true
    },
    "timeReceived": "2019-10-05T17:07:43.211140057Z",
    "timeElapsed": 4.377514958,
    "requestOffset": "",
    "requestId": "zzyko5nodl"
  },
  "blockHash": "0x9f3709512e60699210cf2f8f1786311b9e923f31a5b89656474dc43e102f4294",
  "blockNumber": "52",
  "openapi": "https://zzrtk3l7n1-zzqpc0yvhg-connect.us0-aws.kaleido.io/instances/helloworld?openapi",
  "apiexerciser": "https://zzrtk3l7n1-zzqpc0yvhg-connect.us0-aws.kaleido.io/instances/helloworld?ui",
  "contractAddress": "0xbf835551002a0a802952a3abea9b8981385763fe",
  "cumulativeGasUsed": "162475",
  "from": "0x1fe396e320b71f501b760cc9907215a539ee3409",
  "gasUsed": "162475",
  "nonce": "0",
  "status": "1",
  "to": null,
  "transactionHash": "0xa187acf03973d0fbfd5a825a36a3f4c499ed1300ca66e0e693f6c61ce42b0ff0",
  "transactionIndex": "0",
  "registerAs": "helloworld"
}

Viewing the Named API Proxy

Then if we navigate to the Gateway APIs tab of the Environment, we can see it's known to the whole environment - and hence you can access it from all nodes using that simple /instances/helloworld path.

There is another instance that has been installed without a kld-register friendly name, so the path is a full Ethereum address.

Proxy APIs for Contract Instances Available on Every Node

This is one form of proxy for Smart Contracts. In this case it is an API gateway off-chain proxy, where the Ethereum address is abstracted from the application developers / integration teams.

Note there are other forms of on-chain proxy you might use in combination of these API proxies, to help handle on-chain versioning and data migration.