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
- Base Path:
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, unlesskld-call
is set or the method is read-only (orview
)- 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.
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.
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.