Request-Response
Arbitrary Off-Chain Data Available To Your Smart Contract
Last updated
Arbitrary Off-Chain Data Available To Your Smart Contract
Last updated
A detailed example of how to use the Orakl Network Request-Response can be found at example repository .
The Orakl Network Request-Response serves as a solution to cover a wide range of use cases. While it may not be possible to bring every data feed directly to the blockchain, the Request-Response allows users to specify within their smart contracts the specific data they require and how they should be processed before they are received on-chain. This feature returns data in Single Word Response format, providing users with greater flexibility and control over their data, and allowing them to access a wide range of external data sources.
Orakl Network Request-Response can be used with two different account types that support method:
Permanent Account allows consumers to prepay for Request-Response services, and then use those funds when interacting with Orakl Network. Permanent account is currently a recommended way to request for Request-Response. You can learn more about prepayment payment method or permanent account, go to .
Temporary Account allows user to pay directly for Request-Response without any extra prerequisites. This approach is great for infrequent use, or for users that do not want to hassle with Temporary Account settings and want to use Request-Response as soon as possible.
In this document, we describe both Permanent Account and Temporary Account approaches that can be used for requesting data from off-chain. Finally, we explain and .
We assume that at this point you have already created permanent account through , deposited $KAIA, and assigned consumer(s) to it. If not, , in order to be able to continue in this guide.
After you created account (and obtained accId
), deposited some $KAIA and assigned at least one consumer, you can use it to request data and receive response.
User smart contract that wants to utilize Orakl Network Request-Response has to inherit from abstract fulfillment contracts to support a specific return data type. Currently, we provide the following:
uint128
with RequestResponseConsumerFulfillUint128
int256
with RequestResponseConsumerFulfillInt256
bool
with RequestResponseConsumerFulfillBool
string
with RequestResponseConsumerFulfillString
bytes32
with RequestResponseConsumerFulfillBytes32
bytes
with RequestResponseConsumerFulfillBytes
The estimateFee
function calculates the estimated service fee for a request based on the provided parameters.
Let's understand the purpose and arguments of this function:
numSubmission
: This is a uint8
value representing the number of submissions for the request.
callbackGasLimit
: This is a uint32
value representing the gas limit allocated for the callback function.
By calling the estimateFee()
function with the appropriate arguments, users can get an estimation of the total fee required for their request. This can be useful for spending required amount for each request.
req
: a Request
structure that holds encoded user request
callbackGasLimit
: a uint32
value representing the gas limit for the callback function that executes after the confirmations have been received.
accId
: a uint64
value representing the ID of the account associated with the request.
numSubmission
: requested number of submission from off-chain oracles
The function call requestData()
on COORDINATOR
contract passes req
, accId
, callbackGasLimit
and numSubmission
as arguments. After a successful execution of this function, you obtain an ID (requestId
) that uniquely defines your request. Later, when your request is fulfilled, the ID (requestId
) is supplied together with response to be able to make a match between requests and fulfillments when there is more than one request.
fulfillDataRequest
is a virtual function of RequestResponseConsumerFulfillUint128
abstract smart contract (every RequestResponseConsumerFulfill*
defines this function), and therefore must be overridden. This function is called by RequestResponseCoordinator
when fulfilling the request. callbackGasLimit
parameter defined during data request denotes the amount of gas required for execution of this function.
The arguments of fulfillDataRequest
function are explained below:
requestId
: a uint256
value representing the ID of the request
response
: an uint128
value that was obtained after processing data request sent from requestData
function
This function is executed from RequestResponseCoordinator
contract defined during smart contract initialization. The result is saved in the storage variable sResponse
.
Temporary Account is an alternative type of account which does not require a user to create account, deposit $KAIA, or assign consumer before being able to utilize Request-Response functionality. Request-Response with Temporary Account is only a little bit different compared to Permanent Account, however, the fulfillment function is exactly same.
uint128
with RequestResponseConsumerFulfillUint128
int256
with RequestResponseConsumerFulfillInt256
bool
with RequestResponseConsumerFulfillBool
string
with RequestResponseConsumerFulfillString
bytes32
with RequestResponseConsumerFulfillBytes32
bytes
with RequestResponseConsumerFulfillBytes
There is no difference in initialization of Request-Response consumer contract that requests for data with permanent or temporary account.
The data request using Temporary Account is very similar to request using Permanent Account. The only difference is that for Temporary Account user has to send $KAIA together with call using value
property, and does not have to specify account ID (accId
) as in Permanent Account. There are several checks that have to pass in order to successfully request data. You can read about them in one of the previous subsections called Request data.
This function calls the requestData()
function defined in COORDINATOR
contract, and passes req
, callbackGasLimit
, numSubmission
and refundRecipient
as arguments. The payment for service is sent through msg.value
to the requestData()
in COORDINATOR
contract. If the payment is larger than expected, the exceeding amount is returned to the refundRecipient
address. Eventually, it generates a data request.
In the section below, you can find more detailed explanation of how data request using temporary account works.
In the previous section, we explained that $KAIA is sent together with request for data to RequestResponseCoordinator
which passes the $KAIA deposit to Prepayment
contract. The $KAIA payment stays in the Prepayment
contract until the request is fulfilled.
In rare cases, it is possible that request cannot be fulfilled, and consumer does not receive requested data. To refund deposited $KAIA in such cases, one must first cancel request by calling cancelRequest
inside of RequestResponseCoordinator
and then withdraw $KAIA (withdrawTemporary
) from temporary account inside of Prepayment
contract. In both cases, consumer smart contract has to be the sender (msg.sender
). Our consumer smart contract therefore has to include such auxiliary function(s) to make appropriate calls. If we do not add such functions to consumer contract, it will not be possible to cancel request and withdraw funds deposited to temporary account. Deposited funds will be then forever locked inside of Prepayment
contract.
The code listing below is an example of function inside of consumer contract to cancel and withdraw funds from temporary account.
This function first calculates a fee (fee
) for the request by calling estimateDirectPaymentFee()
function. isDirectPayment
variable indicates whether the request is created through Prepayment or Direct Payment method. Then, it deposits the required fee (fee
) to the account by calling s_prepayment.deposit(accId)
and passing the fee (fee
) as value. If the amount of $KAIA passed by msg.value
to the requestData
is larger than required fee (fee
), the remaining amount is sent back to the caller using the msg.sender.call()
method. Finally, the function returns requestId
that is generated by the requestDataInternal()
function.
This function first calculates a fee for the request by calling estimateFee()
function. Then, it create a temporary account inside of Prepayment contract with sPrepayment.createTemporaryAccount(msg.sender)
call. In the next step, we request data by calling requestData
function. The function has several validation steps, therefore we included requesting for data before depositing the required fee to the account (sPrepayment.depositTemporary{value: fee}(accId)
). If the amount of $KAIA passed by msg.value
to the requestData
is larger than a required fee, the remaining amount is sent back to the refundRecipient
address. Finally, the function returns requestId
that is generated by the internal requestData()
call.
The Orakl Network Request-Response solution enables consumers to define their own requests on-chain, process them by off-chain oracle, and report the results back to consumer smart contract on chain.
uint128
keccak256(abi.encodePacked("uint128")
int256
keccak256(abi.encodePacked("int256")
boolean
keccak256(abi.encodePacked("boolean")
bytes32
keccak256(abi.encodePacked("bytes32")
bytes
keccak256(abi.encodePacked("bytes")
string
keccak256(abi.encodePacked("string")
The job identifier is used to initialize the Orakl.Request
data structure. Once the request is received by the off-chain oracle, it knows what data type to use for final reporting.
Instance of the Orakl.Request
holds all information about consumer's API request and how to post-process the API response. Both request, and post-processing details are inserted to the instance of Orakl.Request
using add
function. The add
function accepts key-value pair parameters, where the first one represents the type of data passed, and the second one is the data itself. The first inserted key has to be get
, and the value has to be a valid API URL.
If the first key is not
get
with valid API URL link as a value, then the request will fail and will not be processed.
The Orakl Network Request-Response currently supports five different post-processing operations that are listed in the table below.
path
list of keys for walk through input JSON
req.add("RAW,ETH,USD,PRICE")
index
Array index
req.add("index", "2");
mul
Multiplication
req.add("mul", "2");
div
Division
req.add("div", "2");
pow10
Multiplication by
req.add("pow10", "8");
All of the above are defined within a file. For the sake of this tutorial, we will demonstrate with RequestResponseConsumerFulfillUint128
only, but the same principles can be applied to other return data types.
Request-Response smart contract () is used both for requesting and receiving data. Address of deployed RequestResponseCoordinator
is used for initialization of parent class RequestResponseConsumerBase
.
reqCount
: This is a uint64
value representing the number of previous requests made. By providing the accId
, you can obtain the reqCount
by invoking the external function getReqCount()
of the
Data request (requestData
) must be called from a contract that has been approved through addConsumer
function of . If the smart contract has not been approved, the request is rejected with InvalidConsumer
error. If account (specified by accId
) does not exist (InvalidAccount
error) or does not have balance high enough, request is rejected as well.
The example code below encodes a request for an ETH/USD price feed from API server. The request describes where to fetch data (), and how to parse (path
and pow10
) the response from API server (shortened version displayed in listing below). The response comes as a nested JSON dictionary on which we want to access RAW
key at first, then ETH
key, USD
key, and finally PRICE
key.
After accessing the ETH/USD price, we notice that the price value is encoded in floating point. To simplify transition of floating point value from off-chain to on-chain, we decide to multiply the price value by 10e8 and keep the value in uint256
data type. This final value is submitted by the off-chain oracle to RequestResponseCoordinator
which consequently calls fulfillDataRequest
function in your consumer smart contract. In the final section of this page, you can learn more about other ways .
Below, you can find an explanation of requestData
function and its arguments defined at :
User smart contract that wants to utilize Orakl Network Request-Response has to inherit from that define what data type we expect as a response.
Request-Response smart contract () is used both for requesting and receiving data. Address of deployed RequestResponseCoordinator
is used for initialization of parent class RequestResponseConsumerBase
.
The following function is defined in .
Requests are created with the help of the . Every request is associated with a job ID which describes what data type it expects to report. The list of currently supported report data types can be found in the table below.