# Introduction

Orakl Network is a decentralized oracle network that allows smart contracts to securely access off-chain data and other resources.

## Installation

> The oracle version `v0.1` and `v0.2` uses Solidity version `^0.8.20`. The version of npm package `@bisonai/orakl-contract` is an internal version of package to recognize changes.

```
yarn add @bisonai/orakl-contracts@v2.0.2
```

The rest of this page describes [Services](#services) and [Payment](#payment) options.

## Services

* [Verifiable Random Function (VRF)](/developers-guide/vrf)
* [Request-Response](/developers-guide/request-response)
* [Data Feed](/developers-guide/data-feed)
* [Proof of Reserve](/developers-guide/proof-of-reserve)

### Verifiable Randomness Function (VRF)

**Verifiable Randomness Function** allows for the generation of random numbers on the blockchain in a verifiable and transparent manner. This can be useful for a wide range of use cases, such as gaming and gambling applications, where a fair and unbiased random number generator is essential.

The detailed information about Orakl Network VRF can be found at [developer's guide on how to use VRF](/developers-guide/vrf). If you want to start using VRF right away, we recommend to look at [an example Hardhat project using Orakl Network VRF](https://github.com/Bisonai/vrf-consumer).

### Request-Response

**Request-Response** allows to query any information off-chain and bring it to your smart contract.

The detailed information about Orakl Network Request-Response can be found at [developer's guide on how to use Request-Response](/developers-guide/request-response). After understanding the basics of Request-Response, you can look at [an example Hardhat project using Orakl Network Request-Response](https://github.com/Bisonai/vrf-consumer).

### Data Feed

**Data Feed** provides a direct on-chain access to the latest off-chain information. The data are collected in a decentralized and secure way through a set of decentralized and reliable operators.

The detailed information about Orakl Network Data Feed can be found at [developer's guide on how to use Data Feed](/developers-guide/data-feed). To get a hands-on experience with Orakl Network Data Feed, we recommend to explore [an example Hardhat project using Orakl Network Data Feed](https://github.com/Bisonai/data-feed-consumer).

### Proof of Reserve

**Proof of Reserve** methods function as security checks for financial institutions, particularly those involved in decentralized finance (DeFi) and blockchain systems.

The detailed information about Orakl Network Proof of Reserve can be found at [developer's guide on how to use Proof of Reserve](/developers-guide/proof-of-reserve). To get a hands-on experience with Orakl Network Proof of Reserve, we recommend to explore [an example Hardhat project using Orakl Network Data Feed](https://github.com/Bisonai/data-feed-consumer).

## Payment & Account Types

The main payment method in Orakl Network is called a [Prepayment](/developers-guide/prepayment). It allows users to deposit $KAIA to their Orakl Network account, and use it to request Orakl Network VRF or Orakl Network Request-Response. We provide two different account types that support the prepayment method:

* [Permanent account](#permanent-account)
* [Temporary account](#temporary-account)

### Permanent account

**Permanent account** allows consumers of Orakl Network to prepay for services, and then use those funds when interacting with Orakl Network. Permanent account is a separate smart contract. It is possible to define a set of consumer smart contracts that can request Orakl Network service through the account without having a direct access to its funds. Permanent account is currently a recommended way to request for both VRF and Request-Response. If you want to learn more about prepayment payment method or permanent account, go to [developer's guide on how to use Prepayment](/developers-guide/prepayment).

### Temporary account

**Temporary account** is designed for casual Orakl Network users who want to pay for the service at the time of the request. The account exists inside of Prepayment contract since the request initiation until its fulfillment, or balance withdrawal. Temporary account can be used to request both VRF and Request-Response.


# Verifiable Randomness Function (VRF)

Undeniably random numbers in your smart contract

A detailed example of how to use Orakl Network VRF can be found at example repository [`vrf-consumer`](https://github.com/Bisonai/vrf-consumer).

## What is Verifiable Randomness Function?

A Verifiable Randomness Function (VRF) is a cryptographic function that generates a random value, or output, based on some input data (called the "seed"). Importantly, the VRF output is verifiable, meaning that anyone who has access to the VRF output and the seed can verify that the output was generated correctly.

In the context of the blockchain, VRFs can be used to provide a source of randomness that is unpredictable and unbiased. This can be useful in various decentralized applications (dApps) that require randomness as a key component, such as in randomized auctions or as part of a decentralized games.

Orakl Network VRF allows smart contracts to use VRF to generate verifiably random values, which can be used in various dApps that require randomness. Orakl Network VRF can be used with two different account types that support [prepayment](/developers-guide/prepayment) method:

* [Permanent Account (recommended)](#permanent-account-recommended)
* [Temporary Account](#temporary-account)

**Permanent Account** allows consumers to prepay for VRF services, and then use those funds when interacting with Orakl Network. Permanent account is currently a recommended way to request for VRF. You can learn more about prepayment payment method or permanent account, go to [developer's guide on how to use Prepayment](/developers-guide/prepayment).

**Temporary Account** allows user to pay directly for VRF 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 VRF as soon as possible.

In the rest of this document, we describe both **Permanent Account** and **Temporary Account** approaches that can be used to request VRF.

## Permanent Account (recommended)

We assume that at this point you have already created permanent account through [`Prepayment` smart contract](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/Prepayment.sol), deposited $KAIA, and assigned consumer(s) to it. If not, [please read how to do all the above](/developers-guide/prepayment), 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 and fulfill random words.

* [Initialization](#initialization)
* [Get estimated service fee](#get-estimated-service-fee)
* [Request random words](#request-random-words)
* [Fulfill-random words](#fulfill-random-words)

User smart contract that wants to use Orakl Network VRF has to inherit from [`VRFConsumerBase` abstract smart contract](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/VRFConsumerBase.sol).

```solidity
import "@bisonai/orakl-contracts/src/v0.1/VRFConsumerBase.sol";
contract VRFConsumer is VRFConsumerBase {
    ...
}
```

### Initialization

VRF smart contract ([`VRFCoordinator`](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/VRFCoordinator.sol)) is used both for requesting random words and for request fulfillments as well. We recommend you to bond `IVRFCoordinator` interface with `VRFCoordinator` address passed as a constructor parameter, and use it for random words requests (`requestRandomWords`).

```solidity
import "@bisonai/orakl-contracts/src/v0.1/VRFConsumerBase.sol";
import "@bisonai/orakl-contracts/src/v0.1/interfaces/IVRFCoordinator.sol";

contract VRFConsumer is VRFConsumerBase {
  IVRFCoordinator COORDINATOR;

  constructor(address coordinator) VRFConsumerBase(coordinator) {
      COORDINATOR = IVRFCoordinator(coordinator);
  }
}
```

### Get estimated service fee

The `estimateFee` function calculates the estimated service fee for a random words request based on the provided parameters.

```solidity
function estimateFee(
    uint64 reqCount,
    uint8 numSubmission,
    uint32 callbackGasLimit
) public view returns (uint256) {
    uint256 serviceFee = calculateServiceFee(reqCount) * numSubmission;
    uint256 maxGasCost = tx.gasprice * callbackGasLimit;
    return serviceFee + maxGasCost;
}
```

Let's understand the purpose and arguments of this function:

* `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 [`Prepayment contract`](https://github.com/Bisonai/orakl/blob/master/contracts/src/v0.1/Prepayment.sol#L212-L214)
* `numSubmission`: This is a `uint8` value representing the number of submissions for the request. The value of `numSubmission` for a VRF request is always `1`.
* `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.

### Request random words

Request for random words must be called from a contract that has been approved through `addConsumer` function of [`Prepayment` smart contract](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/Prepayment.sol). If the smart contract has not been approved, the request is rejected through `InvalidConsumer` error. If account (specified by `accId`) does not exist (`InvalidAccount` error), does not have balance high enough, or uses an unregistered `keyHash` (`InvalidKeyHash` error) request is rejected as well.

```solidity
function requestRandomWords(
    bytes32 keyHash,
    uint64 accId,
    uint32 callbackGasLimit,
    uint32 numWords
)
    public
    onlyOwner
    returns (uint256 requestId)
{
   requestId = COORDINATOR.requestRandomWords(
       keyHash,
       accId,
       callbackGasLimit,
       numWords
   );
}
```

Below, you can find an explanation of `requestRandomWords` function and its arguments defined at [`VRFCoordinator` smart contract](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/VRFCoordinator.sol):

* `keyHash`: a `bytes32` value representing the hash of the key used to generate the random words, also used to choose a trusted VRF provider.
* `accId`: a `uint64` value representing the ID of the account associated with the request.
* `callbackGasLimit`: a `uint32` value representing the gas limit for the callback function that executes after the confirmations have been received.
* `numWords`: a `uint32` value representing the number of random words requested. (maximum 500)

The function call `requestRandomWords()` on `COORDINATOR` contract passes `keyHash`, `accId`, `callbackGasLimit`, and `numWords` 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 random words to be able to make a match between requests and fulfillments when there is more than one request.

### Fulfill random words

`fulfillRandomWords` is a virtual function of [`VRFConsumerBase` smart contract](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/VRFConsumerBase.sol), and therefore must be overridden. This function is called by `VRFCoordinator` when fulfilling the request. `callbackGasLimit` parameter defined during VRF request denotes the amount of gas required for execution of this function.

```solidity
function fulfillRandomWords(
    uint256 /* requestId */,
    uint256[] memory randomWords
)
    internal
    override
{
    // requestId should be checked if it matches the expected request.
    // Generate random value between 1 and 50.
    sRandomWord = (randomWords[0] % 50) + 1;
}
```

The arguments of `fulfillRandomWords` function are explained below:

* `requestId`: a `uint256` value representing the ID of the request
* `randomWords`: an array of `uint256` values representing the random words generated in response to the request

This function is executed from previously defined `COORDINATOR` contract. After receiving random value(s) (`randomWords`) in range of `uint256` data type, it takes the first random element and limits it to a range between 1 and 50. The result is saved in the storage variable `s_randomResult`.

## Temporary Account

**Temporary Account** is an alternative type of account which does not require a user to create account, deposit $KAIA, and assign consumer before being able to utilize VRF functionality. Request for VRF with **Temporary Account** is only a little bit different compared to **Permanent Account**, however, the fulfillment function is exactly same.

* [Initialization with Temporary Account](#initialization-with-temporary-account)
* [Request random words with Temporary Account (consumer)](#request-random-words-with-temporary-account-consumer)
* [Cancel request and receive refund (consumer)](#cancel-request-and-receive-refund-consumer)
* [Request random words with Temporary Account (coordinator)](#request-random-words-with-temporary-account-coordinator)

User smart contract that wants to use Orakl Network VRF has to inherit from [`VRFConsumerBase` abstract smart contract](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/VRFConsumerBase.sol).

```solidity
import "@bisonai/orakl-contracts/src/v0.1/VRFConsumerBase.sol";
contract VRFConsumer is VRFConsumerBase {
    ...
}
```

### Initialization With Temporary Account

There is no difference in initializing VRF user contract that request for VRF with **Permanent Account** or **Temporary Account**.

VRF smart contract ([`VRFCoordinator`](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/VRFCoordinator.sol)) is used both for requesting random words and for request fulfillments as well. We recommend you to bond `IVRFCoordinator` interface with `VRFCoordinator` address passed as a constructor parameter, and use it for random words requests (`requestRandomWords`).

```solidity
import "@bisonai/orakl-contracts/src/v0.1/VRFConsumerBase.sol";
import "@bisonai/orakl-contracts/src/v0.1/interfaces/IVRFCoordinator.sol";

contract VRFConsumer is VRFConsumerBase {
  IVRFCoordinator COORDINATOR;

  constructor(address coordinator) VRFConsumerBase(coordinator) {
      COORDINATOR = IVRFCoordinator(coordinator);
  }
}
```

### Request random words with Temporary Account (consumer)

The request for random words using **Temporary Account** is very similar to request using **Permanent Account**. The only difference is that with a **Temporary Account** user has to send $KAIA together with call using `value` property. There are several checks that have to pass in order to successfully request for VRF. You can read about them in one of the previous subsections called Request random words.

```solidity
function requestRandomWords(
    bytes32 keyHash,
    uint32 callbackGasLimit,
    uint32 numWords,
    address refundRecipient
)
    public
    payable
    onlyOwner
    returns (uint256 requestId)
{
  requestId = COORDINATOR.requestRandomWords{value: msg.value}(
    keyHash,
    callbackGasLimit,
    numWords,
    refundRecipient
  );
}
```

This function calls the `requestRandomWords()` function defined in `COORDINATOR` contract, and passes `keyHash`, `callbackGasLimit`, `numWords` and `refundRecipient` as arguments. The payment for service is sent through `msg.value` to the `requestRandomWords()` in `COORDINATOR` contract. If the payment is larger than expected payment, exceeding payment is returned to the `refundRecipient` address. Eventually, it generates a request for random words. To accurately specify msg.value for the requestRandomWords function, please refer to the explanation on how to [`estimate the service fee`](#get-estimated-service-fee).

In the section below, you can find more detailed explanation of how request for random words using temporary account works.

### Cancel request and receive refund (consumer)

In the previous section, we explained that $KAIA is sent together with request for VRF to `VRFCoordinator` 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 random words. To refund deposited $KAIA in such cases, one must first cancel request by calling `cancelRequest` inside of `VRFCoordinator` 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.

<pre class="language-solidity"><code class="lang-solidity"><strong>function cancelAndWithdraw(
</strong>    uint256 requestId,
    uint64 accId,
    address refundRecipient
) external onlyOwner {
    COORDINATOR.cancelRequest(requestId);
    address prepaymentAddress = COORDINATOR.getPrepaymentAddress();
    IPrepayment(prepaymentAddress).withdrawTemporary(accId, payable(refundRecipient));
}
</code></pre>

### Request random words with Temporary Account (coordinator)

The following function is defined in [`VRFCoordinator` contract](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/VRFCoordinator.sol).

```solidity
function requestRandomWords(
    bytes32 keyHash,
    uint32 callbackGasLimit,
    uint32 numWords,
    address refundRecipient
) external payable nonReentrant onlyValidKeyHash(keyHash) returns (uint256) {
    uint64 reqCount = 0;
    uint8 numSubmission = 1;
    uint256 fee = estimateFee(reqCount, numSubmission, callbackGasLimit);
    if (msg.value < fee) {
        revert InsufficientPayment(msg.value, fee);
    }

    uint64 accId = sPrepayment.createTemporaryAccount(msg.sender);
    bool isDirectPayment = true;
    uint256 requestId = requestRandomWords(
        keyHash,
        accId,
        callbackGasLimit,
        numWords,
        isDirectPayment
    );
    sPrepayment.depositTemporary{value: fee}(accId);

    // Refund extra $KAIA
    uint256 remaining = msg.value - fee;
    if (remaining > 0) {
        (bool sent, ) = refundRecipient.call{value: remaining}("");
        if (!sent) {
            revert RefundFailure();
        }
    }

    return requestId;
}
```

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 for random words by `requestRandomWords` function. The function has several validation steps, therefore we included requesting for random words before depositing the required fee to the account (`sPrepayment.depositTemporary{value: fee}(accId)`). If the amount of $KAIA passed by `msg.value` to the `requestRandomWords` is larger than required fee, the remaining amount is sent back to the `refundRecipient` address. Finally, the function returns `requestId` that is generated by the internal `requestRandomWords()` call.


# Request-Response

Arbitrary Off-Chain Data Available To Your Smart Contract

A detailed example of how to use the **Orakl Network Request-Response** can be found at example repository [`request-response-consumer`](https://github.com/Bisonai/request-response-consumer).

## What is Request-Response?

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 [prepayment](/developers-guide/prepayment) method:

* [Permanent Account (recommended)](#permanent-account-recommended)
* [Temporary Account](#temporary-account)

**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 [developer's guide on how to use Prepayment](/developers-guide/prepayment).

**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 [how to build an on-chain requests](#request) and [how to post-process an API response](#response-post-processing).

## Permanent Account (recommended)

We assume that at this point you have already created permanent account through [`Prepayment` smart contract](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/Prepayment.sol), deposited $KAIA, and assigned consumer(s) to it. If not, [please read how to do all the above](/developers-guide/prepayment), 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.

* [Initialization](#initialization)
* [Get estimated service fee](#get-estimated-service-fee)
* [Request data](#request-data)
* [Receive response](#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`

All of the above are defined within a [RequestResponseConsumerFulfill](https://github.com/Bisonai/orakl/blob/master/contracts/src/v0.1/RequestResponseConsumerFulfill.sol) 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.

```solidity
import { RequestResponseConsumerFulfillUint128 } from "@bisonai/orakl-contracts/src/v0.1/RequestResponseConsumerFulfill.sol";

contract RequestResponseConsumer is RequestResponseConsumerFulfillUint128 {
    ...
}
```

### Initialization

Request-Response smart contract ([`RequestResponseCoordinator`](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/RequestResponseCoordinator.sol)) is used both for requesting and receiving data. Address of deployed `RequestResponseCoordinator` is used for initialization of parent class `RequestResponseConsumerBase`.

```solidity
import { RequestResponseConsumerFulfillUint128 } from "@bisonai/orakl-contracts/src/v0.1/RequestResponseConsumerFulfill.sol";
import { RequestResponseConsumerBase } from "@bisonai/orakl-contracts/src/v0.1/RequestResponseConsumerBase.sol";

contract RequestResponseConsumer is RequestResponseConsumerFulfillUint128 {
  constructor(address coordinator) RequestResponseConsumerBase(coordinator) {
  }
}
```

### Get estimated service fee

The `estimateFee` function calculates the estimated service fee for a request based on the provided parameters.

```solidity
function estimateFee(
    uint64 reqCount,
    uint8 numSubmission,
    uint32 callbackGasLimit
) public view returns (uint256) {
    uint256 serviceFee = calculateServiceFee(reqCount) * numSubmission;
    uint256 maxGasCost = tx.gasprice * callbackGasLimit;
    return serviceFee + maxGasCost;
}
```

Let's understand the purpose and arguments of this function:

* `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 [`Prepayment contract`](https://github.com/Bisonai/orakl/blob/master/contracts/src/v0.1/Prepayment.sol#L212-L214)
* `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.

### Request data

Data request (`requestData`) must be called from a contract that has been approved through `addConsumer` function of [`Prepayment` smart contract](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/Prepayment.sol). 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 <https://min-api.cryptocompare.com/> API server. The request describes where to fetch data (<https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD>), 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.

```json
{
  "RAW": {
    "ETH": {
      "USD": {
        "PRICE": 1754.02
      }
    }
  }
}
```

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 [how to build a request and how to parse the response from off-chain API server](#request).

```solidity
function requestData(
  uint64 accId,
  uint32 callbackGasLimit
)
    public
    onlyOwner
    returns (uint256 requestId)
{
    bytes32 jobId = keccak256(abi.encodePacked("uint128"));
    uint8 numSubmission = 1;
    Orakl.Request memory req = buildRequest(jobId);
    req.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");
    req.add("path", "RAW,ETH,USD,PRICE");
    req.add("pow10", "8");

    requestId = COORDINATOR.requestData(
        req,
        callbackGasLimit,
        accId,
        numSubmission
    );
}
```

Below, you can find an explanation of `requestData` function and its arguments defined at [`RequestResponseCoordinator` smart contract](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/RequestResponseCoordinator.sol):

* `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.

### Receive response

`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.

```solidity
function fulfillDataRequest(
    uint256 /*requestId*/,
    uint128 response
)
    internal
    override
{
    sResponse = response;
}
```

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

**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.

* [Initialization with Temporary Account](#initialization-with-temporary-account)
* [Request data with Temporary Account (consumer)](#request-data-with-temporary-account-consumer)
* [Cancel request and receive refund (consumer)](#cancel-request-and-receive-refund-consumer)
* [Request data with Temporary Account (coordinator)](#request-data-with-temporary-account-coordinator)

User smart contract that wants to utilize Orakl Network Request-Response has to inherit from [one of the following abstract smart contracts](https://github.com/Bisonai/orakl/blob/master/contracts/src/v0.1/RequestResponseConsumerFulfill.sol) that define what data type we expect as a response.

* `uint128` with `RequestResponseConsumerFulfillUint128`
* `int256` with `RequestResponseConsumerFulfillInt256`
* `bool` with `RequestResponseConsumerFulfillBool`
* `string` with `RequestResponseConsumerFulfillString`
* `bytes32` with `RequestResponseConsumerFulfillBytes32`
* `bytes` with `RequestResponseConsumerFulfillBytes`

```solidity
import { RequestResponseConsumerFulfillUint128 } from "@bisonai/orakl-contracts/src/v0.1/RequestResponseConsumerFulfill.sol";

contract RequestResponseConsumer is RequestResponseConsumerFulfillUint128 {
    ...
}
```

### Initialization with Temporary Account

There is no difference in initialization of Request-Response consumer contract that requests for data with permanent or temporary account.

Request-Response smart contract ([`RequestResponseCoordinator`](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/RequestResponseCoordinator.sol)) is used both for requesting and receiving data. Address of deployed `RequestResponseCoordinator` is used for initialization of parent class `RequestResponseConsumerBase`.

```solidity
import { RequestResponseConsumerFulfillUint128 } from "@bisonai/orakl-contracts/src/v0.1/RequestResponseConsumerFulfill.sol";
import { RequestResponseConsumerBase } from "@bisonai/orakl-contracts/src/v0.1/RequestResponseConsumerBase.sol";

contract RequestResponseConsumer is RequestResponseConsumerFulfillUint128 {
  constructor(address coordinator) RequestResponseConsumerBase(coordinator) {
  }
}
```

### Request data with Temporary Account (consumer)

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.

```solidity
receive() external payable {}

function requestData(
  uint32 callbackGasLimit,
  address refundRecipient
)
    public
    payable
    onlyOwner
    returns (uint256 requestId)
{
    bytes32 jobId = keccak256(abi.encodePacked("uint128"));
    uint8 numSubmission = 1;

    Orakl.Request memory req = buildRequest(jobId);
    req.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");
    req.add("path", "RAW,ETH,USD,PRICE");

    requestId = COORDINATOR.requestData{value: msg.value}(
        req,
        callbackGasLimit,
        numSubmission,
        refundRecipient
    );
}
```

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.

### Cancel request and receive refund (consumer)

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.

```solidity
function cancelAndWithdraw(
    uint256 requestId,
    uint64 accId,
    address refundRecipient
) external onlyOwner {
    COORDINATOR.cancelRequest(requestId);
    address prepaymentAddress = COORDINATOR.getPrepaymentAddress();
    IPrepayment(prepaymentAddress).withdrawTemporary(accId, payable(refundRecipient));
}
```

### Request data with Temporary Account (coordinator)

The following function is defined in [`RequestResponseCoordinator` contract](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/RequestResponseCoordinator.sol).

```solidity
function requestData(
    Orakl.Request memory req,
    uint32 callbackGasLimit,
    uint8 numSubmission,
    address refundRecipient
) external payable nonReentrant returns (uint256) {
    uint64 reqCount = 0;
    uint256 fee = estimateFee(reqCount, numSubmission, callbackGasLimit);
    if (msg.value < fee) {
        revert InsufficientPayment(msg.value, fee);
    }

    uint64 accId = sPrepayment.createTemporaryAccount(msg.sender);
    bool isDirectPayment = true;
    uint256 requestId = requestData(
        req,
        accId,
        callbackGasLimit,
        numSubmission,
        isDirectPayment
    );
    sPrepayment.depositTemporary{value: fee}(accId);

    // Refund extra $KAIA
    uint256 remaining = msg.value - fee;
    if (remaining > 0) {
        (bool sent, ) = refundRecipient.call{value: remaining}("");
        if (!sent) {
            revert RefundFailure();
        }
    }

    return requestId;
}
```

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.

## Request & Response Post-Processing

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.

Requests are created with the help of the [Orakl library](https://github.com/Bisonai/orakl/blob/master/contracts/src/v0.1/libraries/Orakl.sol). 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.

<table><thead><tr><th width="245">Response Data Type</th><th>Job ID</th></tr></thead><tbody><tr><td><code>uint128</code></td><td><code>keccak256(abi.encodePacked("uint128")</code></td></tr><tr><td><code>int256</code></td><td><code>keccak256(abi.encodePacked("int256")</code></td></tr><tr><td><code>boolean</code></td><td><code>keccak256(abi.encodePacked("boolean")</code></td></tr><tr><td><code>bytes32</code></td><td><code>keccak256(abi.encodePacked("bytes32")</code></td></tr><tr><td><code>bytes</code></td><td><code>keccak256(abi.encodePacked("bytes")</code></td></tr><tr><td><code>string</code></td><td><code>keccak256(abi.encodePacked("string")</code></td></tr></tbody></table>

### Request

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.

```solidity
bytes32 jobId = keccak256(abi.encodePacked("uint128"));
Orakl.Request memory req = buildRequest(jobId);
```

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.

```solidity
req.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");
```

> 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.

### Response Post-Processing

The **Orakl Network Request-Response** currently supports five different post-processing operations that are listed in the table below.

<table><thead><tr><th width="171.33333333333331">Operation name</th><th width="346">Explanation</th><th>Example</th></tr></thead><tbody><tr><td><code>path</code></td><td>list of keys for walk through input JSON</td><td><code>req.add("RAW,ETH,USD,PRICE")</code></td></tr><tr><td><code>index</code></td><td>Array index</td><td><code>req.add("index", "2");</code></td></tr><tr><td><code>mul</code></td><td>Multiplication</td><td><code>req.add("mul", "2");</code></td></tr><tr><td><code>div</code></td><td>Division</td><td><code>req.add("div", "2");</code></td></tr><tr><td><code>pow10</code></td><td>Multiplication by</td><td><code>req.add("pow10", "8");</code></td></tr></tbody></table>


# Data Feed

Continuous stream of off-chain data to your smart contract

A detailed example of how to use **Orakl Network Data Feed** can be found at example repository [`data-feed-consumer`](https://github.com/Bisonai/data-feed-consumer).

## What is Data Feed?

The Orakl Network data feed is a secure, reliable, and decentralized source of off-chain data accessible to smart contracts on-chain. The data feed is updated at predefined time intervals, or more frequently if the data value deviates more than a predefined threshold, to ensure that the data remains accurate and up-to-date. Data feeds can be used in many different on-chain protocols:

* Lending and borrowing
* Mirrored assets
* Stablecoins
* Asset management
* Options and futures
* and many more!

### Types of Data Feed&#x20;

Orakl Network offers four types of data feeds—**Single**, **Basic**, **Standard**, and **Premium**—each varying in data source, redundancy, and reliability.&#x20;

**Single** **feeds** rely on a single data source, which makes the data more susceptible to manipulation, making it unsuitable for application of VWAP (Volume-Weighted Average Price). Users relying on single feeds are encouraged to implement on-chain protections such as TWAP (Time-Weighted Average Price).&#x20;

In contrast, **Basic** **feeds** aggregate data from 2-4 different sources, **Standard** **feeds** from 5-8, and **Premium** **feeds** from more than 8. These multi-source feeds support the use of VWAP, offering improved accuracy and stronger protection against any manipulation. Generally, the more data sources a feed incorporates, the more reliable and secure it becomes.

### Data Aggregation

The price data are aggregated using the Volume-Weighted Average Price (VWAP) to capture the current market price as accurately as possible. For data feeds that do not provide volume information, median aggregation is utilized.

### Contract Addresses

The Orakl Data Feed includes various data feeds that can be used free of charge. The currently supported data feeds are listed in [datafeeds-addresses.json](https://raw.githubusercontent.com/Bisonai/orakl/master/contracts/v0.2/addresses/datafeeds-addresses.json) configuration file. Other auxiliary addresses can be found at [others-addresses.json](https://raw.githubusercontent.com/Bisonai/orakl/master/contracts/v0.2/addresses/others-addresses.json) configuration file.

## Architecture

The on-chain implementation of Data Feed is composed of two smart contracts: [`Feed`](https://github.com/Bisonai/orakl/blob/master/contracts/v0.2/src/Feed.sol) and [`FeedProxy`](https://github.com/Bisonai/orakl/blob/master/contracts/v0.2/src/FeedProxy.sol). At first,`Feed` and `FeedProxy` are deployed together in pair, representing a single data feed (e.g. temperature in Seoul or price of BTC/USD). `Feed` is being updated at regular intervals by off-chain oracles, and `FeedProxy` is used to access the submitted data to `Feed`. Deployed `FeedProxy` contract represents a consistent API to read data from the feed, and `Feed` contract can be replaced with a newer version.

In the rest of the page, we will focus on [how to read from data feed](#how-to-read-from-data-feed) and [explain relation between `Feed` and `FeedProxy`](#relation-between-feedproxy-and-feed).

## How to read from data feed?

In this section, we will explain how to integrate Orakl Network data feed to your smart contract to be able to read from any data feed. We will also point out potential issues you might encounter and how to solve them.

The section is split into following topics:

* [Initialization](#initialization)
* [Read Data](#read-data)
* [Process Data](#process-data)
* [Time-Weighted Average Price (TWAP)](#time-weighted-average-price-twap)

### Initialization

The access to data feed is provided through the `FeedProxy` address corresponding to a data feed of your choice, and [`IFeedProxy`](https://github.com/Bisonai/orakl/blob/master/contracts/v0.2/src/interfaces/IFeedProxy.sol) from [`@bisonai/orakl-contracts`](https://www.npmjs.com/package/@bisonai/orakl-contracts).

```solidity
import { IFeedProxy } from "@bisonai/orakl-contracts/src/v0.2/interfaces/IFeedProxy.sol";

contract DataFeedConsumer {
    IFeedProxy internal dataFeed;
    constructor(address feedProxy) {
        dataFeed = IFeedProxy(feedProxy);
    }
}
```

### Read Data

Data can be queried from feed using following functions: `latestRoundData()` and `getRoundData(roundId)`.

The `latestRoundData` function returns metadata about the latest submission.

```solidity
(
   uint80 id,
    int256 answer,
    uint updatedAt
) = dataFeed.latestRoundData();
```

Submissions are divided into rounds and indexed by an `id`. Node operators are expected to report submission in every round, and aggregate is computed from all submissions in the same round. Submissions from previous rounds can be queried through `getRoundData` function which requires a single extra parameter `roundId`. The output format is same as from `latestRoundData` function.

```solidity
uint80 roundId =
(
    uint80 id,
    int256 answer,
    uint updatedAt
) = dataFeed.getRoundData(roundId);
```

### Process Data

The values returned from `latestRoundData()` and `getRoundData(roundId)` functions do not include only the data feed value (=`answer`) at corresponding round `id` but also `updatedAt`

`updatedAt` represents the timestamp when the round was updated last time.

> We highly recommend you to keep track of all metadata returned by both `latestRoundData()` and `getRoundData(roundId)`. If your application is dependent on frequent updates, you have to make sure in application layer that data returned by any of these functions is not stale.

`feedProxy` has several other auxiliary functions that should be utilized in order to avoid any issues from misrepresenting the `answer` returned from data feed.

All `answer`s are returned with a specific decimal precision that can be queried using `decimals()` function.

```solidity
uint8 decimals = dataFeed.decimals();
```

`FeedProxy` is always connected to a single `Feed`, but this connection is not fixed and `Feed` can be changed. If you want to make sure that you are still using the same `Feed` you can ask for the `Feed` address through `getFeed()` function.

```solidity
address currentFeed = dataFeed.getFeed()
```

### Use `FeedRouter`

* Conveniently access data feeds using `FeedRouter` contract
* Access all functions in `FeedProxy` by including price pair name as parameter

Initialize FeedRouter that enables access to all supported data feeds.

```solidity
import { IFeedRouter } from "@bisonai/orakl-contracts/src/v0.2/interfaces/IFeedRouter.sol";
contract DataFeedConsumer {
    IFeedRouter internal router;
    constructor(address _router) {
        router = IFeedRouter(_router);
    }
}
```

Read the latest submitted value of given data feed (e.g. "BTC-USDT")

```solidity
(
   uint80 id,
    int256 answer,
    uint updatedAt
) = router.latestRoundData("BTC-USDT");
```

Read value submitted to a given data feed (e.g. "BTC-USDT") for specific roundId.

```solidity
uint80 roundId =
(
    uint80 id,
    int256 answer,
    uint updatedAt
) = router.getRoundData("BTC-USDT", roundId);
```

Get decimals for given data feed (e.g. "BTC-USDT")

```solidity
uint8 decimals = router.decimals("BTC-USDT");
```

Get Feed address associated with given data feed (e.g. "BTC-USDT").

```solidity
address currentFeed = router.feed("BTC-USDT")
```

### Time-Weighted Average Price (TWAP)

The `Feed` contract implements the calculation of TWAP using previously submitted data. In addition to the `Feed` contract, TWAP is accessible through the `FeedProxy` and `FeedRouter` contracts. The calculation is controlled by three parameters: `interval`, `latestUpdatedAtTolerance`, and `minCount`.

* The `interval` represents the time range used for the TWAP calculation, where all values within the range are utilized in the computation.
* The `latestUpdatedAtTolerance` specifies the maximum number of seconds allowed since the last submission to the feed. If the last submission exceeds this tolerance, the TWAP calculation will revert.
* Lastly, the `minCount` parameter defines the minimum number of required data points to compute the TWAP. If the number of data points is insufficient, the calculation will revert.

## Relation between `FeedProxy` and `Feed`

When deploying an`FeedProxy` , `Feed`'s address has to be specified to create a connection between the contracts. Consumer can then request data through `latestRoundData` or `getRoundData` functions, and data will be fetched from `Feed` that is represented by the `feedAddress`.

```solidity
constructor(address _feed) {
    setFeed(_feed);
}
```

At times, it might be necessary to update the address of `Feed`. If the `Feed` address is updated, a queried data feed will come from a different `Feed` than before the update. `FeedProxy`'s update of `Feed` is split into two steps: proposal and confirmation. Both steps can be only executed with `onlyOwner` privileges.

`proposeFeed` stores the proposed address to storage variable and emits event about new address being proposed.

```solidity
 function proposeFeed(address _feed) external onlyOwner {
        if (_feed == address(0)) {
            revert InvalidProposedFeed();
        }
        proposedFeed = IFeed(_feed);
        emit FeedProposed(address(feed), _feed);
    }
```

After the new `Feed` is proposed, one can query a new data feed through a special functions: `latestRoundDataFromProposedFeed` and `getRoundDataFromProposedFeed`. These functions are useful for testing a new data feed, before accepting the new proposed `Feed`.

The function `confirmFeed` is used to finalize the transition to the new proposed `Feed`, and can be executed only with account that has `onlyOwner` privilege. New feed is finalized through `setFeed` (called also inside of `constructor` of `FeedProxy`). Finally, the new feed is announced through emitted event.

```solidity
function confirmFeed(address _feed) external onlyOwner {
        if (_feed != address(proposedFeed)) {
            revert InvalidProposedFeed();
        }
        address previousFeed = address(feed);
        delete proposedFeed;
        setFeed(_feed);
        emit FeedConfirmed(previousFeed, _feed);
    }
```


# Proof of Reserve

Secure delivery of auditable reserve holdings to on-chain

For a comprehensive illustration of utilizing **Orakl Network's Proof of Reserve**, refer to the example repository of the [`data-feed-consumer`](https://github.com/Bisonai/data-feed-consumer). The on-chain implementation for Proof of Reserve mirrors that of the Aggregator and the Aggregator Proxy.

## What is Proof of Reserve?

The **Orakl Network's Proof of Reserve (PoR)** stands as a vital element in fostering trust and transparency within the financial ecosystem of Orakl Network. Playing a pivotal role, PoR is dedicated to the validation of reserve holdings for financial entities through a secure and auditable procedure. The GPC Proof of Reserve refers to a reserved quantity of non-fungible tokens (NFTs) issued specifically for Gold Pegged Coin.

### Proof of Reserve on Cypress

<table><thead><tr><th width="157">PoR</th><th>Aggregator</th><th>AggregatorProxy</th><th>Heartbeat (m)</th></tr></thead><tbody><tr><td>GPC (Gold Pegged Coin)</td><td><a href="https://kaiascan.io/account/0xb5e91e5CE0B8e6fc3029b4E9ce057675a2c96dd1">0xb5e91e5CE0B8e6fc3029b4E9ce057675a2c96dd1</a></td><td><a href="https://kaiascan.io/account/0x9FbA23B10692cB3fa6Fea09834855ACc597BD180">0x9FbA23B10692cB3fa6Fea09834855ACc597BD180</a></td><td>60</td></tr></tbody></table>

### Proof of Reserve on Baobab

**Disclaimer:** The data submitted to Baobab chain and is only for testing purposes. It does not always represent real-world data.

<table><thead><tr><th width="157">PoR</th><th>Aggregator</th><th>AggregatorProxy</th><th>Heartbeat (m)</th></tr></thead><tbody><tr><td>GPC (Gold Pegged Coin)</td><td><a href="https://kairos.kaiascan.io/account/0x58798D6Ca40480DF2FAd1b69939C3D29d91b60d3">0x58798D6Ca40480DF2FAd1b69939C3D29d91b60d3</a></td><td><a href="https://kairos.kaiascan.io/account/0x821179a6d4F62fa6979BF42bEb9eE16a1F14C4eD">0x821179a6d4F62fa6979BF42bEb9eE16a1F14C4eD</a></td><td>2</td></tr></tbody></table>

## How to read from Aggregator contract of PoR

The Proof of Reserve (PoR) in Orakl Network is realized through two key smart contracts: `Aggregator` and `AggregatorProxy`. These contracts form a pair, representing a specific data feed, and enable continuous access to the reserve holdings. The `Aggregator` receives regular updates from off-chain oracles, ensuring accurate and up-to-date reserve information. The `AggregatorProxy` serves as a consistent API for accessing the submitted data.

For a detailed understanding of PoR and its integration, refer to the [Orakl Network Data Feed](/developers-guide/data-feed) documentation. This documentation provides comprehensive insights into the architecture, reading procedures, and the relationship between `Aggregator` and `AggregatorProxy`, enhancing your grasp of PoR functionality.

To learn more about how to read reserves from `Aggregator` contract, visit [`Data Feed documentation`](https://github.com/Bisonai/orakl-docs/blob/master/en/developers-guide/data-feed/README.md#initialization).


# Prepayment

## What is Prepayment?

**Prepayment** is a type of payment solution with a support for two account types: **Temporary Account** and **Permanent Account**. It is implemented within a [`Prepayment` smart contract](https://github.com/Bisonai-CIC/orakl/blob/master/contracts/src/v0.1/Prepayment.sol) and currently it can be used as a payment for Verifiable Random Function (VRF) and Request-Response services.

**Temporary Account** is an account for one-time-use, and it is newly created with every request that takes advantage of this type of account. It is a bit easier to utilize temporary account, therefore it is a good way for initial tests. The account exists only during the lifetime of the associated request and once the request is fulfilled, the account is deleted.

**Permanent Account** offers more features and in the rest of the document we will dive into them. The main components of **Permanent Account** are **Account**, **Account Owner** and **Consumer.**

* **Account owners** are entities that create an account (`createAccount`). They can also close the account (`cancelAccount`), add (`addConsumer`) or remove consumer (`removeConsumer`) from their account(s). $KAIA can be withdrawn from account only by the account owner, however anybody is allowed to deposit (`deposit`) $KAIA to any account.
* **Consumers** assigned to account use the account's balance to pay for Orakl Network services. The ownership of account can be transferred to other entity through a two-step process (`requestAccountOwnerTransfer`, `acceptAccountOwnerTransfer`). Coordinators are smart contracts that can fulfill request issued by consumers, and they distribute rewards to oracles that fulfill requests.

## How to use Permanent Account?

**Permanent Account** can be controlled either controlled through a smart contract interface, or through a web frontend on our [Orakl Network Account page](https://www.orakl.network/account). In this page, we describe how you can access and control permanent account through smart contracts only.

There are [prerequisites](#prerequisites) that you have to do before you can use your **Permanent Account** to pay for Orakl Network services. If you are already experienced with the basic prerequisites, you might be interested in[ other auxiliary functions](#other-functions) defined on Prepayment smart contract.

### Prerequisites

1. [Create account](#create-account)
2. [Deposit $KAIA to account](#deposit-kaia-to-account)
3. [Add consumer](#add-consumer)

#### **Create account**

```solidity
function createAccount() external returns (uint64) {
    uint64 currentAccId = sCurrentAccId + 1;
    sCurrentAccId = currentAccId;

    Account acc = new Account(currentAccId, msg.sender);
    sAccIdToAccount[currentAccId] = acc;

    emit AccountCreated(currentAccId, address(acc), msg.sender);
    return currentAccId;
}
```

This function creates a new account by incrementing a global variable `sCurrentAccId` by 1 and storing the value in a local variable `currentAccId`. Then, it deploys an `Account` smart contract and stores its newly generated address to mapping from account ID to account contract address. Account contracts stores information about owner of the account, sets initial balance to zero, and have no registered consumer smart contracts. Information about newly created account ID and sender's address are emitted using `AccountCreated` event. Finally, it returns the new account ID.

#### **Deposit $KAIA to account**

```solidity
function deposit(uint64 accId) external payable {
    Account account = sAccIdToAccount[accId];
    if (address(account) == address(0)) {
        revert InvalidAccount();
    }
    uint256 amount = msg.value;
    uint256 balance = account.getBalance();

    (bool sent, ) = payable(account).call{value: msg.value}("");
    if (!sent) {
        revert FailedToDeposit();
    }

    emit AccountBalanceIncreased(accId, balance, balance + amount);
}
```

This function retrieves the address of account contract associated with account ID (`accId`). If there is no such account contract, function is reverted (`InvalidAccount`). Received $KAIA are send to account contract. Finally, account balance before and after deposit is emitted through `AccountBalanceIncreased` event.

#### **Add consumer**

```solidity
function addConsumer(uint64 accId, address consumer) external onlyAccountOwner(accId) {
    sAccIdToAccount[accId].addConsumer(consumer);
    emit AccountConsumerAdded(accId, consumer);
}
```

This function makes external call to account contract associated with account ID (`accId`). New consumer is defined as a parameter (`consumer`) and it is added only in case it has not been registered yet. Finally, it emits an event `AccountConsumerAdded` with the account ID and consumer address as arguments.

### Other functions

`Prepayment` smart contract supports many other auxiliary functions. In this document, we describe some of them:

* Transfer account ownership
* Accept account ownership
* Remove consumer
* Cancel account
* Withdraw funds from account

#### **Transfer account ownership**

```solidity
function requestAccountOwnerTransfer(
    uint64 accId,
    address requestedOwner
) external onlyAccountOwner(accId) {
    sAccIdToAccount[accId].requestAccountOwnerTransfer(requestedOwner);
    emit AccountOwnerTransferRequested(accId, msg.sender, requestedOwner);
}
```

This function requests transfer of account ownership from owner of account associated with account ID (`accId`) to `requestedOwner`. `AccountOwnerTransferRequested` indicates that a request for owner transfer has been made for the account.

#### **Accept account ownership**

```solidity
function acceptAccountOwnerTransfer(uint64 accId) external {
    Account account = sAccIdToAccount[accId];
    address newOwner = msg.sender;
    address oldOwner = account.getOwner();
    account.acceptAccountOwnerTransfer(newOwner);
    emit AccountOwnerTransferred(accId, oldOwner, newOwner);
}
```

This function finalizes the transfer of account ownership to the previously proposed `requestedOwner`. This function can be executed only by the `requestedOwner`, otherwise it reverts. `AccountOwnerTransferred` indicates that the transfer of ownership has been completed for the account.

#### **Remove consumer**

```solidity
function removeConsumer(uint64 accId, address consumer) external onlyAccountOwner(accId) {
    sAccIdToAccount[accId].removeConsumer(consumer);
    emit AccountConsumerRemoved(accId, consumer);
}
```

This function makes an external call to account smart contract specified by account ID (`accId`). Within the call, address of `consumer` is removed from the set of registered consumers. Eventually, it emits an event `AccountConsumerRemoved` with the account ID and consumer address as arguments.

#### **Cancel account**

```solidity
function cancelAccount(uint64 accId, address to) external onlyAccountOwner(accId) {
    if (pendingRequestExists(accId)) {
        revert PendingRequestExists();
    }

    Account account = sAccIdToAccount[accId];
    uint256 balance = account.getBalance();
    delete sAccIdToAccount[accId];

    account.cancelAccount(to);

    emit AccountCanceled(accId, to, balance);
}
```

This function checks if there are any pending requests for the account by calling a function `pendingRequestExists(accId)`. If there are any pending requests, the function reverts with the error message `PendingRequestExists()`. If there are no pending requests, we make an external call `cancelAccount` on account contract specified by account ID (`accId`). This call destroys the contract and send all remaining $KAIA to address (`to`) specified as parameter.

#### **Withdraw funds from account**

```solidity
function withdraw(uint64 accId, uint256 amount) external onlyAccOwner(accId) {
    if (pendingRequestExists(accId)) {
        revert PendingRequestExists();
    }

    uint256 oldBalance = s_accounts[accId].balance;
    if ((oldBalance < amount) || (address(this).balance < amount)) {
        revert InsufficientBalance();
    }

    s_accounts[accId].balance -= amount;

    (bool sent, ) = msg.sender.call{value: amount}("");
    if (!sent) {
        revert InsufficientBalance();
    }

    emit AccountBalanceDecreased(accId, oldBalance, oldBalance - amount);
}

function withdraw(uint64 accId, uint256 amount) external onlyAccountOwner(accId) {
    if (pendingRequestExists(accId)) {
        revert PendingRequestExists();
    }

    (bool sent, uint256 balance) = sAccIdToAccount[accId].withdraw(amount);
    if (!sent) {
        revert FailedToWithdraw(accId);
    }

    emit AccountBalanceDecreased(accId, balance + amount, balance);
}
```

This function subtracts the `amount` from the account's balance and transfers the withdrawn amount to the owner of the account using the external call. Finally, it emits an event `AccountBalanceDecreased` with the account ID, old balance and new balance as arguments. `AccountBalanceDecreased` event indicates that the withdrawal has been completed.

#### Other Account types for Fiat and Kaia Subsription

We also have some other account types, which can only be created and updated by our operators. These account types are for fiat (or KAIA) subscription plan.

```solidity
    function createFiatSubscriptionAccount(
        uint256 startDate,
        uint256 period,
        uint256 reqPeriodCount,
        address accOwner
    ) external onlyOwner returns (uint64) {
        uint64 currentAccId = sCurrentAccId + 1;
        sCurrentAccId = currentAccId;

        Account acc = new Account(currentAccId, accOwner, IAccount.AccountType.FIAT_SUBSCRIPTION);
        sAccIdToAccount[currentAccId] = acc;

        acc.updateAccountDetail(startDate, period, reqPeriodCount, 0);

        emit AccountCreated(
            currentAccId,
            address(acc),
            accOwner,
            IAccount.AccountType.FIAT_SUBSCRIPTION
        );
        return currentAccId;
    }
```

```solidity
    function createKlaySubscriptionAccount(
        uint256 startDate,
        uint256 period,
        uint256 reqPeriodCount,
        uint256 subscriptionPrice,
        address accOwner
    ) external onlyOwner returns (uint64) {
        uint64 currentAccId = sCurrentAccId + 1;
        sCurrentAccId = currentAccId;

        Account acc = new Account(currentAccId, accOwner, IAccount.AccountType.KLAY_SUBSCRIPTION);
        sAccIdToAccount[currentAccId] = acc;
        acc.updateAccountDetail(startDate, period, reqPeriodCount, subscriptionPrice);
        emit AccountCreated(
            currentAccId,
            address(acc),
            accOwner,
            IAccount.AccountType.KLAY_SUBSCRIPTION
        );
        return currentAccId;
    }
```

```solidity
   function createKlayDiscountAccount(
        uint256 feeRatio,
        address accOwner
    ) external onlyOwner returns (uint64) {
        uint64 currentAccId = sCurrentAccId + 1;
        sCurrentAccId = currentAccId;
        Account acc = new Account(currentAccId, accOwner, IAccount.AccountType.KLAY_DISCOUNT);
        sAccIdToAccount[currentAccId] = acc;
        acc.setFeeRatio(feeRatio);
        emit AccountCreated(
            currentAccId,
            address(acc),
            accOwner,
            IAccount.AccountType.KLAY_DISCOUNT
        );
        return currentAccId;
    }
```


# L2 Services

Registering and Using Oracle Network Services on L2 Chains

* [Registry Contract](#registry-contract)
* [Endpoint Contracts](#endpoint-contracts)
* [How to Integrate VRF and Request-Response on L2](#how-to-integrate-vrf-and-request-response-on-l2)

## Registry Contract

This contract allows you to manage new chain and Orakl Network services.

### L2 Chain Management

> Please contact [Orakl Network](mailto:business@orakl.network) after you propose a new chain. We will support you to set things up.

1. Propose New Chain and Pay `proposeFee`

```solidity
function proposeNewChain(
    uint256 _chainID,
    string memory _jsonRpc,
    address _endpoint
) external payable {
    if (msg.value < proposeFee) {
        revert NotEnoughFee();
    }
    if (chainRegistry[_chainID].owner != address(0)) {
        revert ChainExisted();
    }
    pendingProposal[_chainID].jsonRpc = _jsonRpc;
    pendingProposal[_chainID].endpoint = _endpoint;
    pendingProposal[_chainID].owner = msg.sender;
    emit ChainProposed(msg.sender, _chainID);
}
```

2. Edit Chain Info

```solidity
function editChainInfo(
    uint256 _chainID,
    string memory _jsonRpc,
    address _endpoint
) external payable onlyConfirmedChainOwner(_chainID) {
    if (msg.value < proposeFee) {
        revert NotEnoughFee();
    }

    chainRegistry[_chainID].jsonRpc = _jsonRpc;
    chainRegistry[_chainID].endpoint = _endpoint;
    emit ChainEdited(_jsonRpc, _endpoint);
}
```

### Account and Payment Functions

Before you can make a request from L2 chain, you need to create and deposit to your account.

1. Create Account

```solidity
function createAccount(uint256 _chainId) external onlyConfirmedChain(_chainId) {
    Account storage newAccount = accounts[nextAccountId];
    newAccount.accId = nextAccountId;
    newAccount.chainId = _chainId;
    newAccount.owner = msg.sender;
    newAccount.balance = 0;
    emit AccountCreated(nextAccountId, _chainId, msg.sender);
    nextAccountId++;
}
```

2. Deposit Funds Into the Account

```solidity
function deposit(uint256 _accId) public payable {
    accounts[_accId].balance += msg.value;
    emit BalanceIncreased(_accId, msg.value);
}
```

3. Add Consumer Into Account

```solidity
function addConsumer(
    uint256 _accId,
    address _consumerAddress
) external onlyAccountOwner(_accId) {
    Account storage account = accounts[_accId];
    require(account.consumerCount < MAX_CONSUMER, "Max consumers reached");

    account.consumers.push(_consumerAddress);
    account.consumerCount++;

    emit ConsumerAdded(_accId, _consumerAddress);
}
```

4. Remove Consumer From Account

```solidity
function removeConsumer(
    uint256 _accId,
    address _consumerAddress
) external onlyAccountOwner(_accId) {
    require(_accId > 0 && _accId < nextAccountId, "Account does not exist");
    Account storage account = accounts[_accId];

    for (uint8 i = 0; i < account.consumerCount; i++) {
        address[] storage consumers = account.consumers;
        if (consumers[i] == _consumerAddress) {
            account.consumerCount--;
            consumers[i] = consumers[account.consumerCount];
            consumers.pop();
            emit ConsumerRemoved(_accId, _consumerAddress);
            return;
        }
    }
}
```

> The consumer address to add or remove to this account is on L2 chain, not mainnet.

## Endpoint Contracts

### `L2Endpoint`

You need to deploy this contract on your chain; it acts as a coordinator for VRF and Request-Response.

1. Request Random Words From L2

```solidity
function requestRandomWords(
    bytes32 keyHash,
    uint64 accId,
    uint32 callbackGasLimit,
    uint32 numWords
) external nonReentrant returns (uint256) {
    sNonce++;
    (uint256 requestId, uint256 preSeed) = computeRequestId(keyHash, msg.sender, accId, sNonce);
    sRequestDetail[requestId] = RequestInfo({
        owner: msg.sender,
        callbackGasLimit: callbackGasLimit
    });
    emit RandomWordsRequested(
        keyHash,
        requestId,
        preSeed,
        accId,
        callbackGasLimit,
        numWords,
        msg.sender
    );

    return requestId;
}
```

2. Request Data From L2

```solidity
function requestData(
    Orakl.Request memory req,
    uint32 callbackGasLimit,
    uint64 accId,
    uint8 numSubmission
) external nonReentrant returns (uint256) {
    sNonce++;
    uint256 requestId = computeRequestId(msg.sender, accId, sNonce);
    sRequestDetail[requestId] = RequestInfo({
        owner: msg.sender,
        callbackGasLimit: callbackGasLimit
    });
    emit DataRequested(
        requestId,
        req.id,
        accId,
        callbackGasLimit,
        msg.sender,
        numSubmission,
        req
    );

    return requestId;
}
```

## How to Integrate VRF and Request-Response on L2

* [VRF](#vrf)
* [Request-Response](#request-response)

### VRF

> Refer to [L2 VRF mock consumer contract](https://github.com/Bisonai/orakl/blob/master/contracts/src/v0.1/mocks/L2VRFConsumerMock.sol).

1. Inherit from the `VRFConsumerBase` Contract

```solidity
contract L2VRFConsumerMock is VRFConsumerBase
```

2. Specify `l2Endpoint` in the Constructor

```solidity
constructor(address l2Endpoint) VRFConsumerBase(l2Endpoint) {
    sOwner = msg.sender;
    L2ENDPOINT = IL2Endpoint(l2Endpoint);
}
```

3. Implement the `requestRandomWords` Function

```solidity
 function requestRandomWords(
    bytes32 keyHash,
    uint64 accId,
    uint32 callbackGasLimit,
    uint32 numWords
) public onlyOwner returns (uint256 requestId) {
    requestId = L2ENDPOINT.requestRandomWords(keyHash, accId, callbackGasLimit, numWords);
}
```

4. Implement the `fulfillRandomWords` Function

```solidity
function fulfillRandomWords(
    uint256 /* requestId */,
    uint256[] memory randomWords
) internal override {
    sRandomWord = (randomWords[0] % 50) + 1;
}
```

### Request-Response

> Refer to [L2 Request-Response mock consumer contract](https://github.com/Bisonai/orakl/blob/master/contracts/src/v0.1/mocks/L2RequestResponseConsumerMock.sol).

1. Inherit from the Base Contract for Request Data Types

```solidity
contract L2RequestResponseConsumerMock is
    RequestResponseConsumerFulfillUint128,
    RequestResponseConsumerFulfillInt256,
    RequestResponseConsumerFulfillBool,
    RequestResponseConsumerFulfillString,
    RequestResponseConsumerFulfillBytes32,
    RequestResponseConsumerFulfillBytes
```

2. Specify `l2Endpoint` in the Constructor

```solidity
constructor(address l2Endpoint) RequestResponseConsumerBase(l2Endpoint) {
    sOwner = msg.sender;
    L2ENDPOINT = IL2Endpoint(l2Endpoint);
}
```

3. Implement `requestData*` Function

```solidity
//request for uint128
function requestDataUint128(
    uint64 accId,
    uint32 callbackGasLimit,
    uint8 numSubmission
) public onlyOwner returns (uint256 requestId) {
    bytes32 jobId = keccak256(abi.encodePacked("uint128"));
    Orakl.Request memory req = buildRequest(jobId);
    //change here for your expected data
    req.add(
        "get",
        "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=KLAY&tsyms=USD"
    );
    req.add("path", "RAW,KLAY,USD,PRICE");
    req.add("pow10", "8");
    requestId = L2ENDPOINT.requestData(req, callbackGasLimit, accId, numSubmission);
}
```

4. Implement the `fulfillDataRequest` Function

```solidity
function fulfillDataRequest(uint256 /*requestId*/, uint128 response) internal override {
    sResponseUint128 = response;
}
```


# Data Availability Layer API (DAL)

Pull-based oracle submission using Data Availability Layer API

The on-chain price data can be updated on-demand by a user through the pull-based oracle. Off-chain price data are updated at sub-second intervals. Users with valid API key can access and [submit the latest price data on-chain](#on-chain-price-data-submission). The price data can be either accessed through [REST API](#rest-api) or [WebSocket API](#websocket-api).

The DAL API requires the `X-API-Key` header. Please [contact us](mailto:business@orakl.network) to receive a valid API key.

## Basic Return Types

| Property      | Type   | Explanation         |
| ------------- | ------ | ------------------- |
| symbol        | string | symbol name         |
| value         | string | price value         |
| aggregateTime | string | timestamp value     |
| proof         | string | proof hexstring     |
| feedHash      | string | feed hash hexstring |
| decimals      | string | decimals            |

### Rest API

* Testnet (REST): <https://dal.baobab.orakl.network>
* Mainnet (REST): <https://dal.cypress.orakl.network>

### GET `/symbols`

returns supported symbols

<details>

<summary>Example Request</summary>

```bash
curl --location --request GET 'https://dal.baobab.orakl.network/symbols' \
--header 'X-API-Key: $API_KEY' \
--header 'Content-Type: application/json'
```

</details>

<details>

<summary>Example Response</summary>

```bash
[
"WAVES-KRW",
"BTC-USDT",
"CHF-USD",
"DAI-USDT",
"JOY-USDT",
"PAXG-USDT",
"GBP-USD",
"WEMIX-USDT",
"ATOM-USDT",
"DOGE-USDT",
"KSP-KRW",
"LTC-USDT",
"TRX-USDT",
"EUR-USD",
"JPY-USD",
"MNR-KRW",
"USDC-USDT",
"XRP-KRW",
"BNB-USDT",
"ETH-KRW",
"ETH-USDT",
"MBX-KRW",
"PER-KLAY",
"BLAST-KRW",
"BTC-KRW",
"DOT-USDT",
"FTM-USDT",
"ZRO-KRW",
"USDT-KRW",
"XRP-USDT",
"AVAX-USDT",
"BORA-KRW",
"KRW-USD",
"SOL-USDT",
"UNI-USDT",
"PEPE-USDT",
"SHIB-USDT",
"SOL-KRW",
"ADA-USDT",
"AKT-KRW",
"KLAY-USDT",
"MATIC-USDT",
"ONDO-KRW"
]
```

</details>

### GET `/latest-data-feeds/all`

returns latest submission parameters for all supported pairs

<details>

<summary>Example Request</summary>

```bash
curl --location --request GET 'https://dal.baobab.orakl.network/latest-data-feeds/all' \
--header 'X-API-Key: $API_KEY' \
--header 'Content-Type: application/json'
```

</details>

<details>

<summary>Example Response</summary>

```bash
[
    {
        "symbol": "BTC-USDT",
        "value": "6426575817343",
        "aggregateTime": "1721886857",
        "proof": "0x6cb90489dddc93c376425355cb497353695e53d91a7d61c3f1e122b1e5c0e2367dc95d36f40d5960784250008ed4a9f18d75b189f0d72eb9e2564e0a05ad374a1c",
        "feedHash": "0xa92bcb5bc51aa5535ed0cc3f522992dd9a6fb2e8dd6dcf484705d93eb3cd167a",
        "decimals": "8"
    },
    {
        "symbol": "ETH-USDT",
        "value": "318659264245",
        "aggregateTime": "1721886857",
        "proof": "0xd7c13dd825dd112de3ce52f704514d60c41f6d34bea3be13fc44a46394376ebd3947bdcb8d8dec9ae2959d1992b99220d4bf60988c7482b9ee98d3079199096b1b",
        "feedHash": "0x7020b52841bb268cbc78137a54d4bf1f5305eed1039fb5d003ba95b8ededc46c",
        "decimals": "8"
    }
    ...
]
```

</details>

### GET `/latest-data-feeds/{symbol,symbol,...}`

returns the latest submission parameters for requested pairs

<details>

<summary>Example Request</summary>

```bash
curl --location --request GET 'https://dal.baobab.orakl.network/latest-data-feeds/all' \
--header 'X-API-Key: $API_KEY' \
--header 'Content-Type: application/json'
```

</details>

<details>

<summary>Example Response</summary>

```bash
[
    {
        "symbol": "BTC-USDT",
        "value": "6426575817343",
        "aggregateTime": "1721886857",
        "proof": "0x6cb90489dddc93c376425355cb497353695e53d91a7d61c3f1e122b1e5c0e2367dc95d36f40d5960784250008ed4a9f18d75b189f0d72eb9e2564e0a05ad374a1c",
        "feedHash": "0xa92bcb5bc51aa5535ed0cc3f522992dd9a6fb2e8dd6dcf484705d93eb3cd167a",
        "decimals": "8"
    },
    {
        "symbol": "ETH-USDT",
        "value": "318659264245",
        "aggregateTime": "1721886857",
        "proof": "0xd7c13dd825dd112de3ce52f704514d60c41f6d34bea3be13fc44a46394376ebd3947bdcb8d8dec9ae2959d1992b99220d4bf60988c7482b9ee98d3079199096b1b",
        "feedHash": "0x7020b52841bb268cbc78137a54d4bf1f5305eed1039fb5d003ba95b8ededc46c",
        "decimals": "8"
    }
    ...
]
```

</details>

### GET `/latest-data-feeds/transpose/all`

returns latest submission paramters for all pairs in transpose format

<details>

<summary>Example Request</summary>

```bash
curl --location 'https://dal.baobab.orakl.network/latest-data-feeds/transpose/all' \
--header 'X-API-Key: $API_KEY'
```

</details>

<details>

<summary>Example Response</summary>

```bash
{
    "symbols": [
        "ADA-USDT",
        "BTC-USDT",
        ...
    ],
    "values": [
        "39386169",
        "6416315907599",
        ...
    ],
    "aggregateTimes": [
        "1721888065",
        "1721888065",
        ...
    ],
    "proofs": [
        "0xb2257cad024889288e0a047d8ab55e0553a9ccafbfbb3ada10392abc2c2bc24c0398189260c4141a3e39b1361445d3d394b2fe0b953b97eaabe9c081dff4c4441b",
        "0x0ad8a61c99bd5b911b37c98d5424c02f7c22afad5b18a434c9e4132a4542da9a2e499b26b75e6e256bc1d77301e5f9edeb62967c3180db2b7b3dbf2c0e8c0c6c1c",
        ...
    ],
    "feedHashes": [
        "0x5f741f7995dc7d3a3a89dd2daccc6c019033c69204605aabf2739c3aa5ec8a62",
        "0xa92bcb5bc51aa5535ed0cc3f522992dd9a6fb2e8dd6dcf484705d93eb3cd167a",
        ...
    ],
    "decimals": [
        "8",
        "8",
        ...
    ]
}
```

</details>

### Get `/latest-data-feeds/transpose/{symbol, symbol..}`

returns latest submission paramters for certain pairs in transpose format

<details>

<summary>Example Request</summary>

```bash
curl --location 'https://dal.baobab.orakl.network/latest-data-feeds/transpose/ADA-USDT,BTC-USDT' \
--header 'X-API-Key: $API_KEY'
```

</details>

<details>

<summary>Example Response</summary>

```bash
{
    "symbols": [
        "ADA-USDT",
        "BTC-USDT"
    ],
    "values": [
        "39386169",
        "6416315907599"
    ],
    "aggregateTimes": [
        "1721888065",
        "1721888065"
    ],
    "proofs": [
        "0xb2257cad024889288e0a047d8ab55e0553a9ccafbfbb3ada10392abc2c2bc24c0398189260c4141a3e39b1361445d3d394b2fe0b953b97eaabe9c081dff4c4441b",
        "0x0ad8a61c99bd5b911b37c98d5424c02f7c22afad5b18a434c9e4132a4542da9a2e499b26b75e6e256bc1d77301e5f9edeb62967c3180db2b7b3dbf2c0e8c0c6c1c"
    ],
    "feedHashes": [
        "0x5f741f7995dc7d3a3a89dd2daccc6c019033c69204605aabf2739c3aa5ec8a62",
        "0xa92bcb5bc51aa5535ed0cc3f522992dd9a6fb2e8dd6dcf484705d93eb3cd167a"
    ],
    "decimals": [
        "8",
        "8"
    ]
}
```

</details>

## WebSocket API

Testnet (WS): <ws://dal.baobab.orakl.network/ws>

Mainnet (WS): <ws://dal.cypress.orakl.network/ws>

### Connect and Request `/ws`

subscribes and pushes price feeds

<details>

<summary>Example Request</summary>

```bash
# connect
websocat ws://dal.baobab.orakl.network/ws -H "X-API-Key: $API_KEY"
# subscribe
{
  "method": "SUBSCRIBE",
  "params": [
    "submission@BTC-USDT"
  ]
}
```

</details>

<details>

<summary>Example Response</summary>

```bash
{
        "symbol": "BTC-USDT",
        "value": "6426575817343",
        "aggregateTime": "1721886857",
        "proof": "0x6cb90489dddc93c376425355cb497353695e53d91a7d61c3f1e122b1e5c0e2367dc95d36f40d5960784250008ed4a9f18d75b189f0d72eb9e2564e0a05ad374a1c",
        "feedHash": "0xa92bcb5bc51aa5535ed0cc3f522992dd9a6fb2e8dd6dcf484705d93eb3cd167a",
        "decimals": "8"
}
```

</details>

## On-chain Price Data Submission

The price data is submitted on-chain through [SubmissionProxy](https://github.com/Bisonai/orakl/blob/master/contracts/v0.2/src/SubmissionProxy.sol) contract. The contract address can be found at [JSON configuration](https://raw.githubusercontent.com/Bisonai/orakl/master/contracts/v0.2/addresses/others-addresses.json).

### `submit` function

Submits in bulk without strict checks. It will silently skip invalid submissions and submit only valid submissions.

#### Signature

```solidity
function submit(
    bytes32[] calldata _feedHashes,
    int256[] calldata _answers,
    uint256[] calldata _timestamps,
    bytes[] calldata _proofs
)
```

#### ABI

```json
[
  {
    "type": "function",
    "name": "submit",
    "inputs": [
      {
        "name": "_feedHashes",
        "type": "bytes32[]",
        "internalType": "bytes32[]"
      },
      {
        "name": "_answers",
        "type": "int256[]",
        "internalType": "int256[]"
      },
      {
        "name": "_timestamps",
        "type": "uint256[]",
        "internalType": "uint256[]"
      },
      {
        "name": "_proofs",
        "type": "bytes[]",
        "internalType": "bytes[]"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  }
]
```

### `submitStrict` function

Submits in bulk with strict checks. If one of the submission entry fails, the whole tx will fail with error

* signature

```solidity
function submitStrict(
        bytes32[] calldata _feedHashes,
        int256[] calldata _answers,
        uint256[] calldata _timestamps,
        bytes[] calldata _proofs
    )
```

* abi

```json
[
  {
    "type": "function",
    "name": "submitStrict",
    "inputs": [
      {
        "name": "_feedHashes",
        "type": "bytes32[]",
        "internalType": "bytes32[]"
      },
      { "name": "_answers", "type": "int256[]", "internalType": "int256[]" },
      {
        "name": "_timestamps",
        "type": "uint256[]",
        "internalType": "uint256[]"
      },
      { "name": "_proofs", "type": "bytes[]", "internalType": "bytes[]" }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  }
]
```

### `submitSingle` function

Submits single entry with checks.

* signature

```solidity
function submitSingle(bytes32 _feedHash, int256 _answer, uint256 _timestamp, bytes calldata _proof)
```

* abi

```json
[
  {
    "type": "function",
    "name": "submitSingle",
    "inputs": [
      { "name": "_feedHash", "type": "bytes32", "internalType": "bytes32" },
      { "name": "_answer", "type": "int256", "internalType": "int256" },
      { "name": "_timestamp", "type": "uint256", "internalType": "uint256" },
      { "name": "_proof", "type": "bytes", "internalType": "bytes" }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  }
]
```

### `submitWithoutSupersedValidation` function

Submit a batch of answers to multiple feeds. The answers are ignored if they have been superseded. If any of the answers do not meet the rest of required conditions the whole batch is reverted.

* signature

```solidity
    function submitWithoutSupersedValidation(
        bytes32[] calldata _feedHashes,
        int256[] calldata _answers,
        uint256[] calldata _timestamps,
        bytes[] calldata _proofs
    )
```

* abi

```json
[
  {
    "type": "function",
    "name": "submitWithoutSupersedValidation",
    "inputs": [
      {
        "name": "_feedHashes",
        "type": "bytes32[]",
        "internalType": "bytes32[]"
      },
      { "name": "_answers", "type": "int256[]", "internalType": "int256[]" },
      {
        "name": "_timestamps",
        "type": "uint256[]",
        "internalType": "uint256[]"
      },
      { "name": "_proofs", "type": "bytes[]", "internalType": "bytes[]" }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  }
]
```

### `submitSingleWithoutSupersedValidation` function

Submit a single submission to a feed. The submission is ignored if it has been superseded. If the submission does not meet the rest of required conditions the submission is reverted.

* signature

```solidity
function submitSingleWithoutSupersedValidation(bytes32 _feedHash, int256 _answer, uint256 _timestamp, bytes calldata _proof)
```

* abi

```json
{
  "type": "function",
  "name": "submitSingleWithoutSupersedValidation",
  "inputs": [
    { "name": "_feedHash", "type": "bytes32", "internalType": "bytes32" },
    { "name": "_answer", "type": "int256", "internalType": "int256" },
    { "name": "_timestamp", "type": "uint256", "internalType": "uint256" },
    { "name": "_proof", "type": "bytes", "internalType": "bytes" }
  ],
  "outputs": [],
  "stateMutability": "nonpayable"
}
```


# Example Projects

Check out example projects to get started

Explore these example projects that showcase the functionality of the Orakl service:

* [Binary Option Application](/developers-guide/example-projects/binary-example): Experience a binary option application that leverages the Orakl network to fetch real-time price data
* [Flipcoin Simulator](/developers-guide/example-projects/flipcoin-example): Dive into an application that utilizes Orakl's Verifiable Random Function (VRF) for generating randomness, simulating the flip of a coin to produce unbiased results of heads or tails.
* [Mystery Box NFT Generator](/developers-guide/example-projects/mystery-box-example): Discover an application that harnesses the power of VRF provided by Orakl to generate unique properties for Non-Fungible Tokens (NFTs), adding an element of unpredictability and rarity to each token.

These examples serve as starting points for developers looking to integrate Orakl's services into their own projects, showcasing its versatility and potential across various use cases.


# Binary Option Example

## Project Description

This project involves the development of a simple decentralized application (DApp) for binary options, showcasing the practical use of data feeds.

### Code repository

The code for this project is available in [binary option orakl](https://github.com/Bisonai/orakl-demo-binary-option). Refer to the readme.md file for detailed instructions on forking the game.

## Disclaimer

Please be aware that binary options trading may be illegal in some jurisdictions. This DApp is purely for educational purposes.

## Key Concept

Upon connecting your wallet to the platform, users are allocated 30 points. These points are used to speculate on the price movements of specified pairs, predicting whether they will rise or fall. The DApp fetches the `latestRoundData()` and compares it with the price at the time of placing the bet.

To access the latest price information for a pair, consult the list of proxy contracts available on the Orakl Network Data Feed.

```solidity
function latestRoundData() external view returns (uint64 id, int256 answer, uint256 updatedAt) {
    return feed.latestRoundData();
}
```


# Flipcoin Example

This project focuses on creating a simple "flip-the-coin" game to demonstrate the usage of the Orakl-VRF (Verifiable Random Function) service.

## Code Repository

The code for this project is available in [Flip Coin Orakl](https://github.com/Bisonai/orakl-demo-flip-coin). Refer to the readme.md file for detailed instructions on forking the game.

### Game Concept

Participants wager an amount and choose either heads or tails in this straightforward game. Successful guesses double the bet, while incorrect guesses result in losing the entire bet.

### Functionality

This game utilizes the Orakl Network's VRF service to generate a random result for the coin flip.

## Parameters Setup

The constructor initializes all necessary parameters for calling the VRF service:

```solidity
constructor(
    uint64 accountId,
    address coordinator,
    bytes32 keyHash
) VRFConsumerBase(coordinator) {
    COORDINATOR = IVRFCoordinator(coordinator);
    sAccountId = accountId;
    sKeyHash = keyHash;
}
```

## Coin Flip Execution

The `flip()` function requests a random number from the VRF to determine the coin flip outcome and records bet details for tracking.

## Result Processing

The fulfillRandomWords function processes the result from the Orakl VRF service. Winnings are calculated based on the outcome, and balances are adjusted accordingly.

## Claiming Winnings

Players can claim their winnings using the `claim()` function, which transfers the winning balance to their account.

## Tax Fee Mechanism

The contract includes a tax fee mechanism, allowing the owner to set the fee with the setTaxFee function. Additionally, the owner can withdraw funds from the contract balance using the withdraw function.

This project serves as an example of integrating Orakl-VRF into a gaming application, demonstrating its ability to provide secure and verifiable random results.


# Mystery Box Example

This project showcases a common scenario in GameFi projects where users purchase NFT (Non-Fungible Token) boxes with the chance to claim a random NFT. In this DApp demo, users can claim the NFT box for free.

The NFT contract utilizes the Orakl VRF (Verifiable Random Function) service to generate a random number between 1 and 10, corresponding to the ID of the rewarded NFT.

## Code repository

The code for this project is available in [mystery box orakl](https://github.com/Bisonai/orakl-demo-mystery-box). Refer to the readme.md file for detailed instructions on forking the game.

## NFT Box Contract

This contract complies with the ERC-721 standard for NFTs and includes additional features.

### Opening a Box

The openBox function requests a random number from the Orakl VRF service, burns the NFT, and rewards the user with the corresponding NFT.

```solidity
function openBox(uint256 _tokenId) public {
    _requireOwned(_tokenId);
    uint256 requestId = requestRandomWords();
    requestIdToPlayer[requestId] = msg.sender;
    _burn(_tokenId);
}
```

### Handling Random Number

The fulfillRandomWords function receives the random number from the Orakl VRF service and mints the corresponding NFT.

```solidity
function fulfillRandomWords(
    uint256 requestId,
    uint256[] memory randomWords
) internal override {
    uint id = randomWords[0] % 10;
    address player = requestIdToPlayer[requestId];
    delete requestIdToPlayer[requestId];
    NFT.mint(player, id, 1, "0x");
}
```

## NFT Contract

This contract follows the ERC-1155 standard for NFTs and includes access control for the mint function.

### Single Mint

```solidity
function mint(
    address account,
    uint256 id,
    uint256 amount,
    bytes memory data
) public onlyRole(MINTER_ROLE) {
    _mint(account, id, amount, data);
}
```

### Batch Mint

```solidity
function mintBatch(
    address to,
    uint256[] memory ids,
    uint256[] memory amounts,
    bytes memory data
) public onlyRole(MINTER_ROLE) {
    _mintBatch(to, ids, amounts, data);
}
```

### Note

Grant the minter role to the box contract to enable it to mint the rewarded NFT.

This project demonstrates how Orakl VRF can introduce randomness into NFT rewards within GameFi ecosystems, enhancing user gaming experiences.


# Introduction

Brief Description Of The Orakl Network For Node Operators

The Orakl Network is a service composed of [hybrid smart contracts](https://blog.chain.link/hybrid-smart-contracts-explained/) utilizing both on-chain and off-chain computation in order to deliver following solutions:

* [Verifiable Random Function (VRF)](/developers-guide/vrf)
* [Request-Response](/developers-guide/request-response)
* [Data Feed](/developers-guide/data-feed)

## On-Chain Orakl Network

On-chain implementation is located under [`contracts` directory](https://github.com/Bisonai/orakl/tree/master/contracts) with all relevant smart contracts, their tests, and deployment scripts. Node operators do not have to be concerned with the content of the `contracts` directory, but they need to know about the up-to-date smart contract addresses and their latests settings in order to setup their nodes properly. In cases, where node operator needs to know more details, we are going to explain all necessary information.

## Off-Chain Orakl Network

Off-chain part is split to several auxiliary micro services, and the main oracle solution:

* [Orakl Network API](/node-operators-guide/api)
* [Orakl Network CLI](/node-operators-guide/cli)
* [Orakl Network Fetcher](broken://pages/RYBvSrFxzacU2aKVVBkJ)
* [Orakl Network VRF](/node-operators-guide/vrf)
* [Orakl Network Request-Response](/node-operators-guide/request-response)
* [Orakl Network Data Feed](/node-operators-guide/data-feed)
* [Orakl Network Proof of Reserve](/node-operators-guide/proof-of-reserve)
* [Orakl Network Delegator](/node-operators-guide/delegator)
* [Helm Chart Infra Setup](broken://pages/nd6EJC0QeESenWoXD0Du)


# Orakl Network API

## Description

The **Orakl Network API** is an abstraction layer representing a single source of truth for Orakl Network deployment. The code is located under [`api` directory](https://github.com/Bisonai/orakl/tree/master/api).

The **Orakl Network API** has to be reachable from every Orakl Network service, and accessible to the [**Orakl Network CLI**](https://github.com/Bisonai/orakl-docs/blob/master/en/node-operators-guide/broken-reference/README.md). It is implemented as a REST web server that accept requests from other services, and the state of the Orakl Network is stored in PostgreSQL database. The **Orakl Network API** has to be launched and configured before any other microservice.

## Configuration

Before we launch the **Orakl Network API**, we must specify [few environment variables](https://github.com/Bisonai/orakl/blob/master/api/.env.example). The environment variables are automatically loaded from a `.env` file. Check example values from `.env.local` file

* `DATABASE_URL`
* `APP_PORT`
* `ENCRYPT_PASSWORD`
* `REDIS_HOST`
* `REDIS_PORT`

`DATABASE_URL` represents a [connection string](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING) to a database that will hold the Orakl Network state.

> The format of `DATABASE_URL` should be `postgresql://[userspec@][hostspec][/dbname][?paramspec]`. An example string can look as follows `postgresql://bisonai@localhost:5432/orakl?schema=public.`

`APP_PORT` represents a port on which the **Orakl Network API** will be running. This port will be necessary when we connect to **Orakl Network API** from other services.

`ENCRYPT_PASSWORD` is an encryption key used for encryption and decryption of private keys inserted to Orakl Network API.

`REDIS_HOST` and `REDIS_PORT` represent host and port of [Redis](https://redis.io/) to which the **Orakl Network API** connect to. The default values are `localhost` and `6379`, respectively. Redis is used to effectively save and load impermanent data

## Launch

To launch the **Orakl Network API** from source code in the production, one must first build the service, and then it can be launched.

```sh
yarn build
yarn start:prod
```

## Architecture

<figure><img src="https://3676787062-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpuVOcZj5hR9fr1RSABE6%2Fuploads%2Fgit-blob-fb94c6411a09ea1621ec3c22cfb1b344c14971b0%2Forakl-network-api.png?alt=media" alt=""><figcaption><p>Orakl Network API</p></figcaption></figure>


# Orakl Network CLI

Take Control Of The Orakl Network With CLI

The **Orakl Network CLI** is a tool to configure and manage the **Orakl Network**. The **Orakl Network CLI** enables access and modifications of the state of the Orakl Network, therefore it is very important tool for node operator. The code is located under [`cli` directory](/developers-guide/data-feed). The configurable parts of the Orakl Network are listed below:

* [Chain](/node-operators-guide/cli/chain)
* [Service](/node-operators-guide/cli/service)
* [Listener](/node-operators-guide/cli/listener)
* [VRF Keys](/node-operators-guide/cli/vrf-keys)
* [Reporter](/node-operators-guide/cli/reporter)
* [Proxy](https://github.com/Bisonai/orakl-docs/blob/master/en/node-operators-guide/cli/proxy.md)
* [Fetcher](https://github.com/Bisonai/orakl-docs/blob/master/en/node-operators-guide/cli/fetcher.md)
* [Delegator](/node-operators-guide/cli/delegator)

### Installation

We recommend to install the **Orakl Network CLI** globally using the command below.

```sh
npx @bisonai/orakl-cli
```

After a successful installation, you can start using it with the same command `npx @bisonai/orakl-cli`. To list all of supported features, you can use the `--help` flag.

```sh
npx @bisonai/orakl-cli --help
```

The output of the `--help` command is displayed below.

```
operator <subcommand>

where <subcommand> can be one of:

- chain
- service
- listener
- vrf
- fetcher
- reporter
- version
- delegator
- proxy

For more help, try running `operator <subcommand> --help`
```

### Setup Alias

The Orakl Network CLI is a tool that node operators will use quite frequently. It might feel clumsy to keep rewriting the `@bisonai/` prefix at every command. To combat that we recommend to create an `orakl-cli` alias for the `@bisonai/orakl-cli` package. The alias can be defined in your shell configuration file (e.g. `.zshrc` or `.bashrc`).

```sh
echo "alias orakl-cli='npx @bisonai/orakl-cli'" >> ~/.zshrc
```

> Do not forget to restart your shell after the configuration file update!

### Configuration

The **Orakl Network CLI** needs to communicate with several services of the Orakl Network in order to perform correctly. The state of the Orakl Network is controlled through the **Orakl Network API**.

To fully configure the **Orakl Network CLI**, setup the following environment variables.

* `ORAKL_NETWORK_API_URL`
* `ORAKL_NETWORK_DELEGATOR_URL`
* `LISTENER_SERVICE_HOST`
* `LISTENER_SERVICE_PORT`
* `WORKER_SERVICE_HOST`
* `WORKER_SERVICE_PORT`
* `REPORTER_SERVICE_HOST`
* `REPORTER_SERVICE_PORT`

`ORAKL_NETWORK_API_URL` and `ORAKL_NETWORK_DELEGATOR_URL` environment variables represent URLs for communication with the **Orakl Network API** and **Orakl Network Delegator**, respectively.

The **Orakl Network CLI** is able to communicate with a specific listener, worker and reporter through **Orakl Network Watchman**. To enable this feature, the **Orakl Network CLI** has to setup environment variables for each service as shown below.

* Listener (`LISTENER_SERVICE_HOST`, `LISTENER_SERVICE_PORT)`
* Worker (`WORKER_SERVICE_HOST`, `WORKER_SERVICE_PORT`)
* Reporter (`REPORTER_SERVICE_HOST`, `REPORTER_SERVICE_PORT)`


# Chain

List, Insert And Remove Orakl Network Chains

The Orakl Network state can hold information about deployments to multiple chains. The chain is a fundamental configuration which is used in all other Orakl Network settings.

The **Orakl Network CLI** provides commands to

* [List Chains](#list-chains)
* [Insert New Chain](#insert-new-chain)
* [Remove Chain Specified By `id`](#remove-chain-specified-by-id)

### List Chains

```sh
orakl-cli chain list
```

```json
[
  { "id": 1, "name": "localhost" },
  { "id": 2, "name": "baobab" },
  { "id": 3, "name": "cypress" }
]
```

### Insert New Chain

If there are not chains set, we can add a new chain using `chain insert` command of the **Orakl Network CLI**.

```sh
orakl-cli chain insert \
    --name ${chainName}
```

* example

```
orakl-cli chain insert --name ethereum
```

### Remove Chain Specified By `id`

Chains can be removed when there are no association to them yet.

```sh
orakl-cli chain remove \
    --id ${id}
```

* example

```sh
orakl-cli chain remove --id 10
```


# Service

List, Insert And Remove Orakl Network Services

The Orakl Network offers several solutions, and each of them has its own specific configuration (e.g. listener setting). Service configuration in the **Orakl Network CLI**, allows to define an arbitrary services that can be associated with higher level solution configuration.

The **Orakl Network CLI** provides commands to

* [List Services](#list-all-services)
* [Insert New Service](#insert-new-service)
* [Remove Service Specified By `id`](#remove-service-specified-by-id)

### List all services

To list all serviced registered in the Orakl Network state, run the command below.

```sh
orakl-cli service list
```

The example output after listing all services can be seen in the listing below. In this case, there are three services: `VRF`, `DATA_FEED` and `REQUEST_RESPONSE`.

```json
[
  { "id": 1, "name": "VRF" },
  { "id": 2, "name": "DATA_FEED" },
  { "id": 3, "name": "REQUEST_RESPONSE" }
]
```

### Insert New Service

A new service can be registered to the Orakl Network state with `service insert` command.

```sh
orakl-cli service insert \
    --name ${name}
```

* example

```sh
orakl-cli service insert --name VRF
```

### Remove Service Specified By `id`

Services that are not associated with any other configuration can be deleted given the service `id`.

```sh
orakl-cli service remove \
    --id ${id}
```

* example

```sh
orakl-cli service remove --id 15
```


# Listener

List, Inser, Remove, Activate And Deactivate Orakl Network Listeners

The **Orakl Network Listener** is a microservice that is part of every Orakl Network solution (VRF, Request-Response). The listener configuration includes [`chain`](/node-operators-guide/cli/chain), [`service`](/node-operators-guide/cli/service), `address` and `eventName` property. The **Orakl Network Listener** listens for an event defined as `eventName` emitted from smart contract `address`.

The **Orakl Network CLI** provides commands to modify both [permanent](#permanent-state) or [ephemeral state](#ephemeral-state) of **Orakl Network Listener**. The list of supported actions is shown below:

* [List Listeners](#list-listeners)
* [Insert New Listener](#insert-new-listener)
* [Remove Listener Specified By `id`](#remove-listener-specified-by-id)
* [List Active Listeners](#list-active-listeners)
* [Activate Listener](#activate-listener)
* [Deactivate Listener](#deactivate-listener)

## Permanent State

The permanent state of listener is loaded on launch of the **Orakl Network Listener** service. It is not accessed by other services such as the **Orakl Network Worker** or the **Orakl Network Reporter**.

### List Listeners

Listeners kept in permanent state can be displayed with `listener list` command. You can filter the listeners by using optional parameters: [`--chain`](/node-operators-guide/cli/chain) or [`--service`](/node-operators-guide/cli/service) .

```sh
orakl-cli listener list \
    [--chain ${chain}] \
    [--service ${service}]
```

* example

```sh
orakl-cli listener list --chain baobab --service DATA_FEED
```

The example output of `listener list` command is displayed below. It includes three different listeners that should listen on three addresses for three different events: `RandomWordsRequested`, `NewRound` and `DataRequested`.

```json
[
  {
    "id": "1",
    "address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0",
    "eventName": "RandomWordsRequested",
    "service": "VRF",
    "chain": "baobab"
  },
  {
    "id": "2",
    "address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853",
    "eventName": "NewRound",
    "service": "DATA_FEED",
    "chain": "baobab"
  },
  {
    "id": "3",
    "address": "0x45778c29A34bA00427620b937733490363839d8C",
    "eventName": "DataRequested",
    "service": "REQUEST_RESPONSE",
    "chain": "baobab"
  }
]
```

To list listeners associated with a specific chain, you can use the `--chain` parameter.

```sh
orakl-cli listener list \
    --chain ${chain}
```

* example

```sh
orakl-cli listener list --chain baobab
```

To list listeners associated with a specific service, you can use the `--service` parameter.

```sh
orakl-cli listener list \
    --service ${service}
```

* example

```sh
orakl-cli listener list --service VRF
```

### Insert New Listener

To insert a new listener to a permanent listener state, you can use the `listener insert` command.

```sh
orakl-cli listener insert \
    --chain ${chain} \
    --service ${service} \
    --address ${address} \
    --eventName ${eventName}
```

* example

```sh
orakl-cli listener insert --chain baobab --service VRF --address 0x123 --eventName RandomWordsRequested
```

### Remove Listener Specified By `id`

Listeners can be removed from a permanent listener state by the `listener remove` command. The listener to remove is specified by its identifier (`--id`).

```sh
orakl-cli listener remove \
    --id ${id}
```

* example

```sh
orakl-cli listener remove --id 72
```

## Ephemeral State

The ephemeral state of listener is created during launch of the **Orakl Network Listener** service, and is used throughout its lifetime until it terminates. All commands from the [Permanent State section](#permanent-state) will not have affect on the ephemeral state unless you apply the `activate` or `deactivate` commands that are described below.

Unlike the permanent listener state, the ephemeral listener state is accessed through a watchman that runs inside of **Orakl Network Listener** service. For this reason, every command that needs an access to ephemeral state has to specify a `--host` and a `--port` parameter that defines the location of the **Orakl Network Listener** service in the network.

### List Active Listeners

All listeners that are part of the permanent state during the launch of the **Orakl Network Listener** service are automatically made active, and can be listed with `listener active` command. [Listeners that are later activated](#activate-listener) will be visible through this command as well. If a listener is not in an active state, it does not listen to the event from its configuration.

```sh
orakl-cli listener active \
    --host ${host} \
    --port ${port}
```

* example

```sh
orakl-cli listener active --host http://127.0.0.1 --port 3030
```

### Activate Listener

Listeners that are added to the permanent listener state after the launch of the **Orakl Network Listener** service are inactive by default. Inactive listeners can be activated by the `listener activate` command with `--id` parameter. The listener identifier can be found through the [`listener list` command](#list-listeners). After a listener becomes active, it starts listening for the events defined in its configuration.

```sh
orakl-cli listener activate \
    --id ${id}
    --host ${host} \
    --port ${port}
```

* example

```sh
orakl-cli listener activate --host http://127.0.0.1 --port 3030
```

### Deactivate Listener

Every new active listener requires an extra computation resource, however, in general it operates with low overhead. When a listener spots an event for which it was listening for, it create a new job for the **Orakl Network Worker**, which then passes new job to the **Orakl Network Reporter**. The consequence of having an extra listener which we do need is an unnecessarily high load on the overall system.

To deactivate listener, and therefore to lower the load on the system, you can use `listener deactivate` command.

```sh
orakl-cli listener deactivate \
    --id ${id}
    --host ${host} \
    --port ${port}
```

* example

```sh
orakl-cli listener deactivate --host http://127.0.0.1 --port 3030
```

> If you do not want to use listener long-term, you should [remove it from the permanent listener state](#remove-listener-specified-by-id), otherwise it will become active after the **Orakl Network Listener** restarts.


# VRF Keys

List, Generate, Insert and Remove Orakl Network VRF Keys

> If you are not an **Orakl Network VRF Node Operator**, you do not need to read the explanation on this page.

The **Orakl Network VRF Worker** needs an access to a private VRF keys (`sk`) to produce a provably random number given the consumer seed (received from on-chain). The **Orakl Network VRF Listener** requires a key hash (`keyHash`) that uniquely represents VRF keys. Typically, an **Orakl Network VRF Node Operator** does not need more than a single set of VRF keys (`pk`, `sk`, `pkX`, `pkY` and `keyHash`).

The **Orakl Network CLI** provides commands to

* [List VRF Keys](#list-vrf-keys)
* [Generate VRF Keys](#generate-vrf-keys)
* [Insert VRF Keys](#insert-vrf-keys)
* [Remove VRF Keys Specified By `id`](#remove-vrf-keys-specified-by-id)

### List VRF Keys

All VRF keys registered in the Orakl Network state can be listed with a `vrf list` command.

```sh
orakl-cli vrf list
```

To display VRF keys that are associated with a specific chain, you can apply an additional `--chain` parameter.

```sh
orakl-cli vrf list \
    --chain ${chain}
```

### Generate VRF Keys

VRF keys can be generated with `vrf keygen` command.

```sh
orakl-cli vrf keygen
```

The `vrf keygen` command produces an output similar to the one below. VRF key generation is random, therefore the output will change with every new run. `sk` represents a private key that should never be shared with anybody who you do not trust.

```
sk=ebeb5229570725793797e30a426d7ef8aca79d38ff330d7d1f28485d2366de32
pk=045b8175cfb6e7d479682a50b19241671906f706bd71e30d7e80fd5ff522c41bf0588735865a5faa121c3801b0b0581440bdde24b03dc4c4541df9555d15223e82
pkX=41389205596727393921445837404963099032198113370266717620546075917307049417712
pkY=40042424443779217635966540867474786311411229770852010943594459290130507251330
keyHash=0x6f32373625e3d1f8f303196cbb78020ac2503acd1129e44b36b425781a9664ac
```

The `vrf keygen` command only generates VRF keys. If you want to use them in the **Orakl Network VRF**, you need to insert them to the Orakl Network state through `vrf insert` command.

### Insert VRF Keys

New VRF keys can be inserted using `vrf insert` command. The command below demonstrates how to insert VRF keys generated by the `vrf keygen` command above and associate with `baobab` chain.

```sh
orakl-cli vrf insert \
    --sk ebeb5229570725793797e30a426d7ef8aca79d38ff330d7d1f28485d2366de32 \
    --pk 045b8175cfb6e7d479682a50b19241671906f706bd71e30d7e80fd5ff522c41bf0588735865a5faa121c3801b0b0581440bdde24b03dc4c4541df9555d15223e82 \
    --pkX 41389205596727393921445837404963099032198113370266717620546075917307049417712 \
    --pkY 40042424443779217635966540867474786311411229770852010943594459290130507251330 \
    --keyHash 0x6f32373625e3d1f8f303196cbb78020ac2503acd1129e44b36b425781a9664ac \
    --chain baobab
```

### Remove VRF Keys Specified By `id`

VRF keys can be removed based on their `id`, using the `--id` parameter applied to `vrf remove` command.

```sh
orakl-cli vrf remove \
    --id ${id}
```


# Reporter

List, Insert, Remove, Activate, Deactivate And Refresh Orakl Network Reporters

> If you are not an **Orakl Network Data Feed Operator**, you do not need to read the explanation on this page.

The **Orakl Network CLI** provides commands to modify both [permanent](#permanent-state) or [ephemeral state](#ephemeral-state) of **Orakl Network Reporter**. The list of supported actions is shown below:

* [List Reporters](#list-reporters)
* [Insert New Reporter](#insert-new-reporter)
* [Remove Reporter Specified By `id`](#remove-reporter-specified-by-id)
* [List Active Reporters](#list-active-reporters)
* [Activate Reporter](#activate-reporter)
* [Deactivate Reporter](#deactivate-reporter)
* [Refresh Reporters](#refresh-reporters)

## What Is Reporter?

Reporter is an abstraction for Externally Owned Account (EOA), as well as for an on-chain oracle that is associated with it. Reporter is allowed to make transactions only to the oracle specified by the address (`oracleAddress`) on a predefined `chain` for a specific `service`.

Reporter metadata are used in all the **Orakl Network** services (**Orakl Network Listener**, **Orakl Network Worker** and **Orakl Network Reporter**).

## Permanent State

The permanent state of reporter is loaded on launch of the **Orakl Network Reporter** service, and accessed on-demand from the **Orakl Network Listener** and the **Orakl Network Worker**.

### List Reporters

All registered reporters can be listed with `reporter list` command. If you want to see only reporters for a specific chain or service, you can use the `--chain` parameter or `--service` parameter, respectively. Both `--chain` and `--service` parameters are optional.

```sh
orakl-cli reporter list \
    [--chain ${chain}] \
    [--service ${service}
```

* example

```sh
orakl-cli reporter list --chain baobab --service VRF
```

### Insert New Reporter

To insert new reporter, one can use the `reporter insert` command. The command requires three groups of commands: EOA-related, oracle-related and category-related. EOA parameters (`--address` and `--privateKey`) are used to create wallet that creates and sends transaction to on-chain smart contract. Oracle parameter (`oracleAddress`) defines which smart contract can be executed by this reporter's wallet. The **Orakl Network** uses a single EOA for each smart contract in order to limit scalability issues when multiple transaction are issued from the same wallet around the same time. Lastly, category parameters (`--chain` and `--service`) are used to for reporter separation by chain and service, respectively.

```sh
orakl-cli reporter insert \
  --chain ${chain} \
  --service ${service} \
  --address ${address} \
  --privateKey ${privateKey} \
  --oracleAddress ${oracleAddress}
```

* example

```sh
orakl-cli reporter insert --chain baobab --service VRF --address 0x12 --privateKey abc12 --oracleAddress 0xab
```

### Remove Reporter Specified By `id`

The reporter can be removed from the **Orakl Network** state anytime, however, it won't have an immediate impact on the ephemeral state of **Orakl Network**. If you need an immediate change inside of your **Orakl Network Reporter service**, use `reporter deactivate` command.

Reporter can be removed using the `reporter remove` command supplied with an extra `--id` parameter that represents an identifier of the reporter.

```sh
orakl-cli reporter remove \
    --id ${id}
```

* example

```sh
orakl-cli reporter remove --id 15
```

## Ephemeral State

The ephemeral state of reporter is created during launch of the **Orakl Network Reporter** service, and is used throughout its lifetime until it terminates. All commands from the [Permanent State section](#permanent-state) will not have affect on the ephemeral state unless you apply the `activate`, `deactivate` or `refresh` commands that are described below.

Unlike the permanent reporter state, the ephemeral reporter state is accessed through a watchman that runs inside of **Orakl Network Reporter** service. For this reason, every command that needs an access to ephemeral state has to specify a `--host` and a `--port` parameter that defines the location of the **Orakl Network Reporter** service in the network.

### List Active Reporters

All reporters that are part of the permanent state during the launch of the **Orakl Network Reporter** service are automatically made active, and can be listed with `reporter active` command. [Reporters that are later activated](#activate-reporter) will be visible through this command as well. If reporter is not in an active state, it cannot send transaction to its assigned oracle.

```sh
orakl-cli reporter active \
    --host ${host} \
    --port ${port}
```

* example

```sh
orakl-cli reporter active --host 127.0.0.1 --port 3030
```

### Activate Reporter

Reporters that are added to the permanent reporter state after the launch of the **Orakl Network Reporter** service are inactive by default. Inactive reporters can be activated by the `reporter activate` command with `--id` parameter. The reporter identifier can be found through the [`reporter list` command](#list-reporters). After reporter becomes active, it can start submitting requested transaction to the chain.

```sh
orakl-cli reporter activate \
    --id ${id}
    --host ${host} \
    --port ${port}
```

* example

```sh
orakl-cli reporter activate --id 15 --host 127.0.0.1 --port 3030
```

### Deactivate Reporter

The number of active reporter does not affect required resources for the **Orakl Network Reporter** service, however from time to time, you might need to deactivate some of your active reporters. To deactivate reporter, you can use `reporter deactivate` command.

```sh
orakl-cli reporter deactivate \
    --id ${id}
    --host ${host} \
    --port ${port}
```

* example

```sh
orakl-cli reporter deactivate --id 15 --host 127.0.0.1 --port 3030
```

> If you do not want to use reporter long-term, you should [remove it from the permanent reporter state](#remove-reporter-specified-by-id), otherwise it will become active after the **Orakl Network Reporter** restarts.

### Refresh Reporters

Sometimes, it might be faster to sync permanent reporter state with ephemeral reporter state. If you need to set ephemeral reporter state to the permanent one, you can use `reporter refresh` command.

```sh
orakl-cli reporter refresh \
    --host ${host} \
    --port ${port}
```

* example

```sh
orakl-cli reporter refresh --host 127.0.0.1 --port 3030
```


# Fetcher

Start And Stop Data Collection


# Delegator

Register organization, reporters, contracts, functions, and connect them together to create your white list rules

### Insert new organization

```sh
yarn cli delegator organizationInsert \
    --name ${orgName}
```

* example

```sh
yarn cli delegator organizationInsert --name bisonai
```

### List organizations

```sh
yarn cli delegator organizationList
```

### Insert new reporter

```sh
yarn cli delegator reporterInsert \
      --address ${address} \
      --organizationId ${organizationId}
```

* example

```sh
yarn cli delegator reporterInsert --address 0xab --organizationId 10
```

### List reporters

```sh
yarn cli delegator reporterList
```

### Insert new contract

```sh
yarn cli delegator contractInsert \
      --address ${address}
```

* example

```sh
yarn cli delegator contractInsert --address 0x23
```

### List contracts

```sh
yarn cli delegator contractList
```

### Insert new function

```sh
yarn cli delegator functionInsert \
      --name ${functionSignature} \
      --contractId ${contractId}
```

* example

```sh
yarn cli delegator functionInsert --name "submit(int256,uint256)" --contractId 15
```

### List functions

```sh
yarn cli delegator functionList
```

### Connect contract with reporter

```sh
yarn cli delegator contractConnect \
      --contractId 1 \
      --reporterId 1
```

### List reporters

```
yarn cli delegator reporterList
```


# Orakl Network VRF

## Description

The **Orakl Network VRF** is one of the main Orakl Network solutions. It provides an access to provably random number generator.

The code is located under [`core` directory](https://github.com/Bisonai/orakl/tree/master/core), and separated to three independent microservices: listener, worker and reporter.

## State Setup

The **Orakl Network VRF** requires an access to state of listeners and VRF keys.

### Listener

The **Orakl Network API** holds information about all listeners. The command below adds a single VRF listener to the Orakl Network state to listen on `vrfCoordinatorAddress` for `RandomWordsRequested` event. The `chain` parameter specifies a chain on which we expect to operate with the **Orakl Network VRF Listener**.

```sh
orakl-cli listener insert \
    --service VRF \
    --chain ${chain} \
    --address ${vrfCoordinatorAddress} \
    --eventName RandomWordsRequested
```

* example

```sh
orakl-cli listener insert --service VRF --chain baobab --address 0xDA8c0A00A372503aa6EC80f9b29Cc97C454bE499 --enventName RandomWordsRequested
```

### Reporter

The **Orakl Network API** holds information about all reporters. The command below adds a single VRF reporter to the Orakl Network state to report to `oracleAddress`. The chain parameter specifies a chain on which we expect to operate. Reporter is defined by an `address` and a `privateKey` parameters.

```sh
orakl-cli reporter insert \
  --service VRF \
  --chain ${chain} \
  --address  ${address} \
  --privateKey ${privateKey} \
  --oracleAddress ${oracleAddress}
```

* example

```sh
orakl-cli reporter insert \
  --service VRF \
  --chain baobab \
  --address  0x12 \
  --privateKey abc \
  --oracleAddress 0xDA
```

### VRF Keys

To be able to run VRF as a node operator, one must have registered VRF keys in [`VRFCoordinator`](https://github.com/Bisonai/orakl/blob/master/contracts/src/v0.1/VRFCoordinator.sol), and VRF keys has to be in Orakl Network state as well. VRF worker will load them from the **Orakl Network API** when it is launched.

If you do not have VRF keys, you can generate them with the **Orakl Network CLI** using the following command.

```sh
orakl-cli vrf keygen
```

The output of generated command will be similar to the one below, but including the keys on the right side of the keys (`sk`, `pk`, `pkX`,`pkY`, and `keyHash`). VRF keys are generated randomly, therefore every time you call the `keygen` command, you receive a different output. `sk` represents a secret key which is used to generate the VRF `beta` and `pi`. This secret key should never be shared with anybody except the required personnel.

```
sk=
pk=
pkX=
pkY=
keyHash=
```

To store VRF keys in Orakl Network state use `orakl-cli vrf insert` command. Parameter `--chain` corresponds to the network name to which VRF keys will be associated.

```sh
orakl-cli vrf insert \
    --chain ${chain} \
    --pk ${pk} \
    --sk ${sk} \
    --pkX ${pkX} \
    --pkY ${pkY} \
    --keyHash ${keyHash}
```

## Configuration

Before we launch the **Orakl Network VRF**, we must specify [several environment variables](https://github.com/Bisonai/orakl/blob/master/core/.env.example). The environment variables are automatically loaded from a `.env` file.

* `NODE_ENV=production`
* `CHAIN`
* `PROVIDER_URL`
* `ORAKL_NETWORK_API_URL`
* `LOG_LEVEL`
* `REDIS_HOST`
* `REDIS_PORT`
* `HEALTH_CHECK_PORT`
* `SLACK_WEBHOOK_URL`

The **Orakl Network VRF** is implemented in Node.js which uses `NODE_ENV` environment variable to signal the execution environment (e.g. `production`, `development`). [Setting the environment to `production`](https://nodejs.org/en/learn/getting-started/nodejs-the-difference-between-development-and-production) generally ensures that logging is kept to a minimum, and more caching levels take place to optimize performance.

`CHAIN` environment variable specifies on which chain the **Orakl Network VRF** will be running, and which resources will be collected from the **Orakl Network API**.

`PROVIDER_URL` defines an URL string representing a JSON-RPC endpoint that listener and reporter communicate through.

`ORAKL_NETWORK_API_URL` corresponds to url where the **Orakl Network API** is running. The **Orakl Network API** interface is used to access Orakl Network state such as listener and VRF key configuration.

Setting a level of logs emitted by a running instance is set through `LOG_LEVEL` environment variable, and can be one of the following: `error`, `warning`, `info`, `debug` and `trace`, ordered from the most restrictive to the least. By selecting any of the available options you subscribe to the specified level and all levels with lower restrictiveness.

`REDIS_HOST` and `REDIS_PORT` represent host and port of [Redis](https://redis.io/) to which all **Orakl Network VRF** microservices connect. The default values are `localhost` and `6379`, respectively.

The **Orakl Network VRF** does not offer a rich REST API, but defines a health check endpoint (`/`) served under a port denoted as `HEALTH_CHECK_PORT`.

Errors and warnings emitted by the **Orakl Network VRF** can be [sent to Slack channels through a slack webhook](https://api.slack.com/messaging/webhooks). The webhook URL can be set with the `SLACK_WEBOOK_URL` environment variable.

## Launch

Before launching the VRF solution, the **Orakl Network API** has to be accessible from the **Orakl Network VRF** to load VRF keys, and listener settings.

After the **Orakl Network API** is healthy, launch the VRF service, which consists of listener, worker, and reporter microservices, with the command below. Microservices communicate with each other through the BullMQ - job queue.

```sh
yarn start:core:vrf
```

Run in dev mode through the following command:

```sh
yarn dev:core:vrf
```

It's also possible to run the microservices separately in any arbitrary order:

```sh
yarn start:listener:vrf
yarn start:worker:vrf
yarn start:reporter:vrf
```

## Quick launch with Docker

From [orakl](https://github.com/Bisonai/orakl) repository's root, run the following command to build all images:

```bash
docker-compose -f docker-compose.local-core.yaml build
```

Set wallet credentials, `ADDRESS` and `PRIVATE_KEY` values, in the [.core-cli-contracts.env](https://github.com/Bisonai/orakl/blob/master/dockerfiles/local-vrf-rr/envs/.core-cli-contracts.env) file. Keep in mind that the default chain is `localhost`. If changes are required, update `CHAIN` (other options being `baobab` and `cypress`) and `PROVIDER_URL` values. Note that if the chain is not `localhost`, `Coordinator` and `Prepayment` contracts won't be deployed. Instead, Bisonai's already deployed [contract addresses](https://github.com/Bisonai/vrf-consumer/blob/9b06ddd10b472d821878c9994463856664387c85/hardhat.config.ts#L60-L68) will be used. After setting the appropriate `.env` values, run the following command to start the VRF service:

```bash
SERVICE=vrf docker-compose -f docker-compose.local-core.yaml up --force-recreate
```

**Note** that the current docker implementation is designed to run a single service, either `rr` or `vrf`, at a time. Therefore, it's highly recommended to add `--force-recreate` when running `docker-compose up` command. That will restart all containers thus removing all the modified data in those containers.

Here is what happens after the above command is run:

* `api`, `postgres`, `redis`, and `json-rpc` services will start as separate docker containers
* `postgres` will get populated with necessary data:
  * chains
  * services
  * vrf keys
  * listener (after contracts are deployed)
  * reporter (after contracts are deployed)
* migration files in `contracts/v0.1/migration/` get updated with provided keys and other values
* if the chain is `localhost`:
  * `contracts/v0.1/hardhat.config.cjs` file gets updated with `PROVIDER_URL`
  * relevant coordinator and prepayment contracts get deployed

## Architecture

<figure><img src="https://3676787062-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpuVOcZj5hR9fr1RSABE6%2Fuploads%2Fgit-blob-496a4acd67672829f5bb4120e9d0b6a2738dfb45%2Forakl-network-vrf.png?alt=media" alt=""><figcaption><p>Orakl Network VRF</p></figcaption></figure>


# Orakl Network Request-Response

## Description

The **Orakl Network Request-Response** is one of the main Orakl Network solutions. It provides an access to off-chain data from on-chain smart contracts. Requests are emitted through on-chain event, captured by the **Orakl Network Request-Response Listener**, processed by the **Orakl Network Request-Response Worker** and eventually responded back to on-chain through the **Orakl Network Request-Response Reporter**.

The code is located under [`core` directory](https://github.com/Bisonai/orakl/tree/master/core), and separated to three independent microservices: listener, worker and reporter.

## State Setup

The **Orakl Network Request-Response** requires an access to state for listeners and reporters.

### Listener

The **Orakl Network API** holds information about all listeners. The command below adds a single Request-Response listener to the Orakl Network state to listen on `requestResponseCoordinatorAddress` for `DataRequested` event. The `chain` parameter specifies a chain on which we expect to operate with the **Orakl Network Request-Response Listener**.

```sh
orakl-cli listener insert \
    --service REQUEST_RESPONSE \
    --chain ${chain} \
    --address ${requestResponseCoordinatorAddress} \
    --eventName DataRequested
```

* example

```sh
orakl-cli listener insert \
    --service REQUEST_RESPONSE \
    --chain baobab \
    --address 0x12 \
    --eventName DataRequested
```

### Reporter

The **Orakl Network API** holds information about all reporters. The command below adds a single Request-Response reporter to the Orakl Network state to report to `oracleAddress`. The chain parameter specifies a chain on which we expect to operate. Reporter is defined by an `address` and a `privateKey` parameters.

```sh
orakl-cli reporter insert \
  --service REQUEST_RESPONSE \
  --chain ${chain} \
  --address  ${address} \
  --privateKey ${privateKey} \
  --oracleAddress ${oracleAddress}
```

* example

```sh
orakl-cli reporter insert \
  --service REQUEST_RESPONSE \
  --chain baobab \
  --address  0xab \
  --privateKey abc \
  --oracleAddress ${oracleAddress}
```

## Configuration

Before we launch the **Orakl Network Request-Response**, we must specify [several environment variables](https://github.com/Bisonai/orakl/blob/master/core/.env.example). The environment variables are automatically loaded from a `.env` file.

* `NODE_ENV=production`
* `CHAIN`
* `PROVIDER_URL`
* `ORAKL_NETWORK_API_URL`
* `LOG_LEVEL`
* `REDIS_HOST`
* `REDIS_PORT`
* `HEALTH_CHECK_PORT`
* `SLACK_WEBHOOK_URL`

The **Orakl Network Request-Response** is implemented in Node.js which uses `NODE_ENV` environment variable to signal the execution environment (e.g. `production`, `development`). [Setting the environment to `production`](https://nodejs.org/en/learn/getting-started/nodejs-the-difference-between-development-and-production) generally ensures that logging is kept to a minimum, and more caching levels take place to optimize performance.

`CHAIN` environment variable specifies on which chain the **Orakl Network Request-Response** will be running, and which resources will be collected from the **Orakl Network API**.

`PROVIDER_URL` defines an URL string representing a JSON-RPC endpoint that listener and reporter communicate through.

`ORAKL_NETWORK_API_URL` corresponds to url where the **Orakl Network API** is running. The **Orakl Network API** interface is used to access Orakl Network state such as listener configuration.

Setting a level of logs emitted by a running instance is set through `LOG_LEVEL` environment variable, and can be one of the following: `error`, `warning`, `info`, `debug` and `trace`, ordered from the most restrictive to the least. By selecting any of the available options you subscribe to the specified level and all levels with lower restrictiveness.

`REDIS_HOST` and `REDIS_PORT` represent host and port of [Redis](https://redis.io/) to which all **Orakl Network Request-Response** microservices connect. The default values are `localhost` and `6379`, respectively.

The **Orakl Network Request-Response** does not offer a rich REST API, but defines a health check endpoint (`/`) served under a port denoted as `HEALTH_CHECK_PORT`.

Errors and warnings emitted by the **Orakl Network Request-Response** can be [sent to Slack channels through a slack webhook](https://api.slack.com/messaging/webhooks). The webhook URL can be set with the `SLACK_WEBOOK_URL` environment variable.

## Launch

Before launching the Request-Response solution, the **Orakl Network API** has to be accessible from the **Orakl Network Request-Response** to load listener settings.

After the **Orakl Network API** is healthy, launch the Request-Response service, which consists of listener, worker, and reporter microservices, with the command below. Microservices communicate with each other through the BullMQ - job queue.

```sh
yarn start:core:request_response
```

Run in dev mode through the following command:

```sh
yarn dev:core:request_response
```

It's also possible to run the microservices separately in any arbitrary order:

```sh
yarn start:listener:request_response
yarn start:worker:request_response
yarn start:reporter:request_response
```

## Quick launch with Docker

From [orakl](https://github.com/Bisonai/orakl) repository's root, run the following command to build all images:

```bash
docker-compose -f docker-compose.local-core.yaml build
```

Set wallet credentials, `ADDRESS` and `PRIVATE_KEY` values, in the [.core-cli-contracts.env](https://github.com/Bisonai/orakl/blob/master/dockerfiles/local-vrf-rr/envs/.core-cli-contracts.env) file. Keep in mind that the default chain is `localhost`. If changes are required, update `CHAIN` (other options being `baobab` and `cypress`) and `PROVIDER_URL` values. Note that if the chain is not `localhost`, `Coordinator` and `Prepayment` contracts won't be deployed. Instead, Bisonai's already deployed [contract addresses](https://github.com/Bisonai/request-response-consumer/blob/376de8136c6ae22ac7c8769bb8e72085146d018f/hardhat.config.ts#L44C5-L54C6) will be used. After setting the appropriate `.env` values, run the following command to start the Request-Response service:

```bash
SERVICE=rr docker-compose -f docker-compose.local-core.yaml up --force-recreate
```

**Note** that the current docker implementation is designed to run a single service, either `rr` or `vrf`, at a time. Therefore, it's highly recommended to add `--force-recreate` when running `docker-compose up` command. That will restart all containers thus removing all the modified data in those containers.

Here is what happens after the above command is run:

* `api`, `postgres`, `redis`, and `json-rpc` services will start as separate docker containers
* `postgres` will get populated with necessary data:
  * chains
  * services
  * listener (after contracts are deployed)
  * reporter (after contracts are deployed)
* migration files in `contracts/v0.1/migration/` get updated with provided keys and other values
* if the chain is `localhost`:
  * `contracts/v0.1/hardhat.config.cjs` file gets updated with `PROVIDER_URL`
  * relevant coordinator and prepayment contracts get deployed

## Architecture

The architecture is very similar to the **Orakl Network VRF**. The only difference is that the **Orakl Network Request-Response Worker** fetches and processes data based on the on-chain request.

<figure><img src="https://3676787062-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpuVOcZj5hR9fr1RSABE6%2Fuploads%2Fgit-blob-61e8bdab4d87c581d27d702da0247d90023f8287%2Forakl-network-request-response.png?alt=media" alt=""><figcaption><p>Orakl Network Request-Response</p></figcaption></figure>


# Orakl Network Data Feed

## Description

The **Orakl Network Data Feed** is one of the main Orakl Network solutions. The goal of the **Orakl Network Data Feed** is to provide frequent data updates from off-chain to on-chain. The data feed is created from a submission pool that is composed of most up-to-date values reported by verified node operators.

A single data feed is defined by [config](https://config.orakl.network/config/baobab/ADA-USDT.config.json), and can be accessed on-chain through a `FeedProxy` smart contract. The `FeedProxy` is an auxiliary contract that redirects read requests to `Feed` contract. The `Feed` contract holds all submissions from all node operators, and aggregated value that is served to consumers through `FeedProxy` contract.

Detailed specification for each feeds can be found in [orakl-config](https://github.com/Bisonai/orakl-config) as `configs.json` file. Every data feed is configured with 3 different intervals. `fetchInterval`, `aggregateInterval`, and `submitInterval`. `OraklNode`, which stands for new datafeed performing off-chain aggregation, will execute each jobs based on defined intervals. Datafeed is updated once the finalized value have been generated off chain among OraklNodes. `address` stands for the Feed contract address which takes the value for certain pair. `feeds` contains definitions to fetch and parse value from datasource.

The code is located under [`node` directory](https://github.com/Bisonai/orakl/tree/master/node) and it follows modular monolith pattern. The entrypoints can be found from `./node/cmd` directory, and its implementation codes can be found from `./node/pkg` directory.

## Setup and run

Please refer to [README.md](https://github.com/Bisonai/orakl/blob/master/node/README.md) in `./node` directory.

## Architecture

<figure><img src="https://3676787062-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpuVOcZj5hR9fr1RSABE6%2Fuploads%2Fgit-blob-871745363a2c21d88a887dd9e8dcd7547dc2c44d%2Forakl-network-node.png?alt=media" alt=""><figcaption><p>Orakl Network Data Feed (Offchain Aggregation)</p></figcaption></figure>


# Orakl Network Delegator

Whitelist Fee Delegation Service

## Description

The **Orakl Network Delegator** is a [fee delegation](https://docs.kaia.io/learn/transactions/fee-delegation/) micro-service that verify incoming transaction based on customized whitelist rules, and sign them as a fee payer when they are eligible. The code is located under [`delegator` directory](https://github.com/Bisonai/orakl/tree/master/delegator).

## API Endpoints

The **Orakl Network Delegator** accepts transactions from registered EOAs of the **Orakl Network Reporter**, validates them based on customized whitelist rules, and finally signs them with a fee payer account. The **Orakl Network Delegator** is implemented as a REST web server, and all the transactions and related metadata are stored in the PostgreSQL database.

### Sign Transaction

To sign the transaction you can use `api/v1/sign` endpoint.

```shell
curl -X 'POST' \
  'http://localhost:3000/api/v1/sign' \
  -H 'accept: */*' \
  -H 'Content-Type: application/json' \
  -d '{
  "from": "string",
  "to": "string",
  "input": "string",
  "gas": "string",
  "value": "string",
  "chainId": "string",
  "gasPrice": "string",
  "nonce": "string",
  "v": "string",
  "r": "string",
  "s": "string",
  "rawTx": "string",
  "signedRawTx": "string"
}'
```

### Organization

The first step is to add an organization name.

To add a new organization name, you can use `api/v1/organization` endpoint.

```shell
curl -X 'POST' \
  'http://localhost:3000/api/v1/organization' \
  -H 'accept: */*' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "Bisonai"
}'
```

### Reporter

Next step is to connect a reporter address with organization.

To add a new reporter, you can use `api/v1/reporter` endpoint.

```shell
curl -X 'POST' \
  'http://localhost:3000/api/reporter' \
  -H 'accept: */*' \
  -H 'Content-Type: application/json' \
  -d '{
  "address": "string",
  "organizationId": 0
}'
```

### Contract

After defining teporter, the next step is to add a contract address of the service to the whitelist. Currently, [whitelist has to include function selector](#function-whitelist) as well.

To add a new contract, you can use `api/v1/contract` endpoint.

```shell
curl -X 'POST' \
  'http://localhost:3000/api/v1/contract' \
  -H 'accept: */*' \
  -H 'Content-Type: application/json' \
  -d '{
  "address": "string"
}'
```

### Function

After adding the contract address, the next step is to define which function methods are allowed to be executed inside of specific contract address.

To add a new function name, you can use `api/v1/function` endpoint.

```shell
curl -X 'POST' \
  'http://localhost:3000/api/v1/function' \
  -H 'accept: */*' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "increment()",
  "contractId": 1,
  "encodedName": ""
}'
```

### Connect Reporter

The last step is to connect reporter with contract.

To add a new whitelist connection, you can use `api/v1/contract/connectReporter` endpoint.

```shell
curl -X 'POST' \
  'http://localhost:3000/api/v1/contract/connectReporter' \
  -H 'accept: */*' \
  -H 'Content-Type: application/json' \
  -d '{
  "contractId": 0,
  "reporterId": 0
}'
```

## Configuration

Before we launch the **Orakl Network Delegator**, we must specify [few environment variables](https://github.com/Bisonai/orakl/blob/master/delegator/.env.example). The environment variables are automatically loaded from an `.env` file.

* `DATABASE_URL`
* `PROVIDER_URL`
* `APP_PORT`

`DATABASE_URL` represents a [connection string](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING) to a database that will hold the **Orakl Network** state.

> The format of `DATABASE_URL` should be `postgresql://[userspec@][hostspec][/dbname][?paramspec]`. An example string can look as follows `postgresql://bisonai@localhost:5432/orakl?schema=public.`

`PROVIDER_URL` defines an URL string representing a JSON-RPC endpoint that listener, worker, and reporter communicate through.

`APP_PORT` represents a port on which the **Orakl Network Delegator** will be running. This port will be necessary when we connect to **Orakl Network Delegator** from other services.

`DELEGATOR_FEEPAYER_PK` is the private key of delegator account which signs all transactions as a fee payer.

`DELEGATOR_REPORTER_PK` is the private key of reporter account makes transactions within the **Orakl Network Reporter** service. This private key is used only in tests.

## Launch

Before launching the **Orakl Network Delegator**, one must add delegator's private key to `privateKey` column inside of `fee_payers` table. This private key will be used to sign [delegated fee transactions](https://docs.kaia.io/learn/transactions/fee-delegation/) as a fee payer.

To launch the Orakl Network Delegator from source code in the production, first build the service, and then launch it.

```sh
yarn build
yarn start:prod
```

Once the Orakl Network Delegator is launched, we must load the `privateKey` to be able able to sign transactions. `privateKey` can be loaded by calling `/api/v1/sign/initialize` endpoint.

## Architecture

<figure><img src="https://3676787062-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpuVOcZj5hR9fr1RSABE6%2Fuploads%2Fgit-blob-aef48393464b9ee6026f1f7cb908fc5c2b39f366%2Forakl-network-delegator.png?alt=media" alt=""><figcaption><p>Orakl Network Delegator</p></figcaption></figure>


# Orakl Network Proof of Reserve

## Description

The **Orakl Network Proof of Reserve** is a critical component within the Orakl Network ecosystem, designed to establish and verify the reserve holdings of financial entities. This service ensures transparency and trust in the financial operations by providing a secure and auditable process for validating reserve data. The Orakl Network Proof of Reserve is a cornerstone within the ecosystem, dedicated to establishing trust in financial operations. This service seamlessly integrates off-chain and on-chain processes, providing a robust framework to verify and authenticate reserve holdings.

A Proof of Reserve is defined by a pair of an adapter and an aggregator, and can be accessed on-chain through a `AggregatorProxy` smart contract, where the on-chain implementation of contracts are reused from [contracts v0.1](https://github.com/Bisonai/orakl/tree/d1cde6fcd0845c07391b6a7f28f9f83ca911ad54/contracts/v0.1). The `AggregatorProxy` is an auxiliary contract that redirects read requests to `Aggregator` contract. The Proof of Reserve's `Aggregator` contract holds all submission values that is served to consumers through `AggregatorProxy` contract.

Every proof of reserve has configuration that describes the least frequent update interval called `heartbeat`, and minimum deviation threshold (`deviationTreshold`).

The **Orakl Network Proof of Reserve** operates as a streamlined, single-process system, easily triggered by a Cron job. The initial phase involves retrieving the most recent `roundId` and `PoR value` from the Proof of Reserve `Aggregator contract`. Subsequently, the process assesses eligibility for submission through a combination of the `Heartbeat Check` and `Deviation Check`. If either condition is met, the final step involves fetching data from the `API resource` and reporting the next round to the `POR contract`. This cohesive workflow ensures efficient and timely execution of the `Proof of Reserve` process.

The code is located under [./node/pkg/por](https://github.com/Bisonai/orakl/tree/master/node/pkg/por) directory

## Configuration

Before we launch the **Orakl Network Proof of Reserve**, we must specify [several environment variables](https://github.com/Bisonai/orakl/blob/master/node/.env.example). The environment variables are automatically loaded from a `.env` file.

```.env
# POR
POR_REPORTER_PK=
POR_CHAIN=
POR_PROVIDER_URL=
# (optional) defaults to 3000
POR_PORT=
```

* `POR_REPORTER_PK`: designated por reporter's pk, should be whitelisted from the aggregator contract
* `POR_CHAIN`: chain name of POR (`baobab` or `cypress`)
* `POR_PROVIDER_URL`: json rpc url to be used for reading and submitting onchain
* `POR_PORT`: port to be used for healthcheck (defaults to `3000`)

## Launch

Before launch, setup environment variables required by Orakl Node. You can find detailed explanation at [Orakl Node README](https://github.com/Bisonai/orakl/blob/master/node/README.md).

To launch Proof Of Reserve navigate to `node` directory and execute the command below.

```sh
task local:por
```


# Audit

We prioritize the security of the Orakl Network and conduct thorough audits for every update to our on-chain architecture. These audits are essential to identify and address vulnerabilities, ensuring the ongoing integrity and trustworthiness of our platform.

{% file src="/files/TQWGfkyqzhejlvGASKrs" %}

{% file src="/files/Lk4URH9Iw8TyD5zgPPJ5" %}

{% file src="/files/st5RyaAFuhLZnHMSh1Fq" %}


# White paper

{% file src="/files/S6RzJJ7nGpfUgdN7Yprr" %}


# Social Media

* [Website](https://www.orakl.network/)
* [Twitter](https://twitter.com/OraklNetwork)
* [Medium](https://oraklnetwork.medium.com/)
* [Kaia Dev Forum (English)](https://devforum.kaia.io/c/english/orakl-network/52)
* [Kaia Dev Forum (한국어)](https://devforum.kaia.io/c/38-category/orakl-network/51)


# Terms of Use

### **01. Purpose**

These Terms of Use (the "Terms" or "Terms of Use") set forth the relationship between Orakl Network ("Company", "we", "us", or "our"), a provider of the oracle service ("Orakl" or "Service"), and the Users. Please read these Terms of Use carefully before using the Service.

### **02. Definition of Terms**

1. “Service” or “Orakl” refers to a Kaia native oracle that provides Data Feed, VRF. Request-Response solutions and Proof of Reserve (POR).
2. “Blockchain” refers to technology that stores data in an electronic block and connects each block sequentially like a chain, and records the transaction details in a ledger that anyone can read and duplicates it on each computer participating in the blockchain network. It refers to a distributed data storage method that stores.
3. “Smart contract” refers to a bundle of codes written in a language that can be operated as a program on Kaia.
4. “Digital Assets” refers to all data on the blockchain, including coins, tokens, and NFTs, as a means of storing value and a medium of exchange in an electronic way through services.
5. “KAIA” refer to Token that is commonly used within Kaia, a unique blockchain platform.
6. "Token" refers to digital assets in the form of coins or tokens issued through smart contracts on the Kaia main chain.
7. “NFT” refers to a Non-fungible Token that has a unique key value.
8. "Member"(or "User") refers to an individual who executes a use contract with the Company (the Use Agreement”) in accordance with these Terms of Use and uses the Services provided by the Company.
9. “Account” refers to an account created to identify the person in the Service, and refers to a service account that is granted to a User who agrees to these Terms of Use and executes the Use Agreement with the Company.
10. “Kaia Account Address” refers to a unique identification address that exists on Kaia to record changes in digital assets between Users in the Service.
11. "Password" refers to a combination of numbers and letters set by the User for confidentiality and confirming that the User is a user matching the Account and account address.
12. “Kaia Wallet Key” refer to a unique combination of letters and numbers used or required for all smart contract operations such as transmission, transaction, and signing of digital assets held by the account address.
13. The definitions of terms used in the Terms are in accordance with relevant laws and general business practices, except for those specified in the preceding paragraph.

### 03. Modification of the Terms of Use

1. The Company shall display the Terms of Use on the main (initial) page of its Service so that Users can check and learn the content thereof with ease.
2. The Company may change part or the entirety of these Terms of Use to the extent that such amendment does not violate relevant laws such as the Act on the Regulation of Terms and Conditions (the “ARTC”) and the Act on Promotion of Information and Communications Networks Utilization and Information Protection (the “Information and Communications Network Act” or the “ICNA”).
3. Upon changing any part of these Terms of Use, the Company shall announce the plan to do so, along with the current Terms of Use and clearly indicating the date upon which the change is to take effect as well as the cause(s) for the change, on the main (initial) page of its Service 15 days before said change is to take effect. Should the Company change these Terms of Use in a way that disadvantages Users or significantly affects the rights and obligations of the Users, the Company shall publicly announce from no later than 30 days prior to the effective date until the day before such effective date, and individually inform the Users whose phone numbers or emails are collected through the relevant means.
4. While the Company clearly and separately notified (or if the User whose individual notification means have not been collected is notified of the following during the period specified in Paragraph 3) that the a User who did not express their intention to object to the revised Terms of Use by the effective date notified or individually informed in accordance with the Paragraph 3 would be deemed to have provided its consent to the revised Terms of Use, if such User failed to explicitly indicate its intention to object to such revised Terms of Use and continues to use the Service after the effective date of the revised Terms of Use, such User shall be deemed to have consented to the revised Terms of Use.
5. If the User does not agree with the revised Terms of Use, the User may discontinue use of the Service and terminate the Use Agreement. Where there are exceptional circumstances making it impossible for a Company to continue to apply the old Terms of Use, the Company may first terminate the Use Agreements with users who refuse to accept the changed Terms of Use.

### 04. Other Binding Rules

1. The Company may indicate details in its operation policy in connection with use of the Service within the scope determined in these Terms of Use.
2. For matters not defined in these Terms of Use and the interpretation of these Terms, the applicable laws of the Republic of Korea and the general conventions of commerce shall apply.
3. The Company may require separate consent to a separate operation policy (including, without limitation, the Paid Service Standard Contract) for specific services among the Services provided by the Company. In this case, the User would be allowed to review the separate operation policy and freely agree to it in the process of using the Service, and may use the individual service within the agreed scope.

### 05. Entering the Use Agreement

1. A user that wishes to become a member (the “applicant”) shall indicate consent to these Terms of Use and submit its application. The Use Agreement is entered into effect when the Company approves the application.
2. The Company reserves the right to withhold approval of, or latently terminate Use Agreements signed on the basis of, applications in the following cases:
   1. Where the applicant has had the experience of having its sign-up revoked pursuant to these Terms of Use in the past (except for applicant users that have secured Company authorization to seek sign-up again);
   2. Where the applicant has provided false or misleading information, or use of someone else's name;
   3. Where the applicant has faults or its own or violated other laws, rules, etc. that prevent the approval of its application;
   4. Where the applicant resides in a jurisdiction according to whose law using the Service may constitute an illegal or criminal act;
   5. If an applicant determines that the purpose of using the Service for anti-social or illegal purposes;
   6. If the applicant breaches any of the responsibilities of the User as provided in the Article 10 herein;
   7. Where the applicant is under the age of 19;
3. Where it is impossible to accept new applications due to lack of room in service facilities, or other technical/administrative reasons, the Company may reserve the approval of applications.
4. In principle, the Company is to inform applicants of their applications being denied or reserved due to reasons enumerated in Paragraphs 2 and 3 if the Company has contact information of the applicant.
5. The Use Agreement is deemed effective as of the moment upon which the applicant has agreed to the Terms of Use, submitted its application, and the Company has accepted it.

### 06. Personal Information

In the event that the Company collects personal information, the Company strives to protect all Users’ personal information in accordance with the applicable laws, including the Personal Information Protection Act (hereinafter the “PIPA”) and the ICNA. Applicable laws as well as the Company’s own Privacy Policy apply to the use and protection of Users’ personal information. However, the Company's personal information processing policy does not apply to linked sites other than the Company's official site.

### 07. User Obligations Concerning Password

1. Users have the duty to protect and manage their own passwords. They are not to lend, transfer, or otherwise allow the use of such information by third parties.
2. Upon confirming that their password or other parts of protected information are being used by unauthorized third parties, Users must immediately inform the Company and follow its instructions on the handling thereof.
3. The Company shall not be held responsible for losses or damage that may arise due to Users’ failure to inform the Company and/or follow its instructions pursuant to Paragraph 2, unless there is intentional or negligence on the part of the Company.
4. The Company shall not be held responsible for losses or damage that Users may suffer due to the loss, theft, or unauthorized disclosure of their access information, including passwords, except in cases where such losses have occurred due to deliberate acts or negligence by Company.

### 08. Notification of Users

1. When the Company notifies users of information related to the Service for the operation of the Service, the Company notifies users individually in a reasonable manner such as email of the user held by the Company.
2. In the case of notification to all users, the Company can replace the notification in Paragraph 1 by posting it through Service for more than 7 days. In the event of notification of content that adversely affects or significantly affects the rights and obligations of the Users, individual notice shall be given in accordance with Paragraph 1, 30 days prior to the effective date (or, if the Company has not collected individual notification means relating to the User, the notification may be replaced by making public announcement for more than 30 days).

### 09. Responsibilities of the Company

1. The Company shall not engage in conduct or acts that are prohibited by applicable laws or the Terms of Use and/or that run contrary to the good and fine customs of society. It shall strive to provide stable services without interruption.
2. The Company shall adopt security systems and solutions to protect Users’ personal information, and disclose and abide by its Privacy Policy.
3. The Company shall hire the necessary personnel and systems to ensure appropriate handling of Users’ complaints and requests for remedies regarding their use of Services.
4. Where Users make valid claims or complaints regarding Services, the Company shall act to remedy the situation. The Company may use its electronic emails, etc. to inform Users of the status and outcomes of their claims or complaints.

### 10. Responsibilities of Users

1. Users shall refrain from the following:
   1. Providing false information upon applying for sign-up or updating User information;
   2. Misappropriating/stealing third parties’ information;
   3. Altering information posted/displayed by the Company;
   4. Transmitting or displaying information (including computer programs) other than that provided by the Company;
   5. Infringing upon copyrights and other intellectual property rights of the Company and/or third parties;
   6. Defaming the reputation or interrupting operations of the Company and/or third parties;
   7. Posting/displaying information of obscene and/or violent nature, whether in the forms of texts, videos or voices;
   8. Misappropriating the Company’s Services for profit making purposes without the Company’s consent;
   9. Use of the Service in an unusual way;
   10. The act of using the Service for the purpose of motivating and executing illegal activities;
   11. Illegal activities such as multi-level and similar deposit-taking;
   12. Other illicit, unethical and/or criminal acts.
2. Users shall comply with the applicable laws, these Terms of Use, and the Company's policy and instructions regarding the use and appropriation of its Services. They shall refrain from acts or conduct that could interfere with the Company’s operations.
3. When using the Service, the User shall not transfer the authority to a third party or receive compensation for the use of the Service (all tangible or intangible compensation such as money and information).
4. The User shall not reproduce, store, process, distribute, or provide the result data of the Service to a third party without the prior consent of the Company.

### 11. Copyright

1. The copyright of the Services and related programs provided by the Company belongs to the Company.
2. Users must not infringe the copyright of the Company or a third party when using the Service.
3. Copyright or use rights for the results through the Service are not deemed to have been acquired by the User.
4. When creating or using a screen using the Service, the User must specify that it is the result of the Service. However, if the Company has a separate display method, it shall be followed.

### 12. Service Type and Provision

1. The Company provides the following Service to Users.
   1. Provide on-chain data feed
   2. Allow Users to call any APIs via Request-Response
   3. Generate random numbers via VRF (Verifiable Random Function)
   4. Proof of Reserve (PoR)
2. Please refer to the website (<https://www.orakl.network/>) for detailed regulations of the type and content of the Service according to the preceding paragraph.
3. The Company can set the scope of the Service, the available time, and the number of times of use, and the User may use the Service only according to the service provision conditions set by the Company. The Company will notify Users in accordance with Article 8 so that Users can check.
4. Service fee may be charged for using the Service provided by the Company and a User using the Service shall abide by the policy including terms of the fee designated and amended by the Company from time to time.
5. The Company may temporarily suspend the provision of Services in the event of maintenance, inspection, replacement, or breakdown of information and communication facilities such as computers, communication disruption, or significant operational reasons. In this case, the Company will notify the User in accordance with Article 8, except for unavoidable reasons that cannot be notified.
6. The Company may conduct regular inspections to provide smooth Service, and there may be restrictions on some or all parts of the Service. The Company notifies the Users of necessary matters for periodic inspection, and is not liable for any damages incurred unless there is intention or negligence of the Company.
7. The Company is not responsible for any incorrect input or request by the User through the Service.
8. The Company notifies Users when some functions within the Service are restricted due to service failure or maintenance of a third party connected to the Service. We are not responsible for any problems arising from this, unless there is intentional or negligence of the Company.

### 13. Using Paid Services

1. The Company provides the Service for free, but some or parts of the Service are limited and may be provided for a fee.
2. In principle, when using the paid service provided by the Company, the User must pay the usage fee according to the Paid Service Standard Contract before using it. The payment method and period of payment for the paid service provided by the Company shall be in accordance with the Paid Service Standard Contract.
3. The Company may request additional information from Users to fulfill payment according to the Paid Service Standard Contract.
4. Detailed regulations for paid services, such as use, restriction, and termination of paid services, shall follow the Paid Service Standard Contract. In this case, if there is a conflict between this Terms and the Paid Service Standard Contract, the Paid Service Standard Contract shall prevail.

### 14. Method of payment

1. The payment method for using the paid service can be made by any of the following methods.

#### Prepayment

Prepayment allows consumers of Orakl Network to prepay for services in KAIA, and then using those funds when interacting with Orakl Network.

#### Direct Payment

Direct Payment method allows to use Orakl Network's services without requiring to create any account in advance. All services can be requested and paid at the time of the request in KAIA.\\

2. Members must use the payment method in their own name when using the payment method of Paragraph 1 for payment of paid services, and must not use another person's payment method arbitrarily. Members are responsible for all damages to the Company, the legitimate owner of the payment method, and a third party related to payment that may occur by using the payment method of another person arbitrarily, unless there is intentional or negligence on the part of the Company.
3. The information entered by the Member in connection with the payment and the responsibilities and disadvantages incurred in connection with the information shall be borne by the Member, unless there is intentional or negligence on the part of the Company.
4. The Member must use a payment method with proper usage rights when making payment, and the Company can verify this. In addition, the Company may stop the transaction or cancel the transaction until it confirms that the Member's payment method is legitimate.
5. Depending on the Company's policy, the cumulative payment amount of the Member may be limited.
6. To ensure more convenience on the part of the Users, more payment methods may be added in addition to those stated in Paragraph 1.

### 15 (KAIA as Payment Method)

1. The Company may allow KAIA as a payment method as defined in Article 2. Payment using KAIA shall only be possible for single payments.
2. The User shall comply with the payment policies set forth by the Company when using KAIA as a payment method. The Company shall display the payment policies on the payment page of its Service so that Users may check and learn the content thereof with ease.
3. In the following cases, the Company may restrict approval until the reasons for limiting approval for payment applications are resolved.
4. In case of service failure
5. In case of inspection or failure of the payment

### 16. Modification or Suspension of the Service

1. The Company may change part or all of the Service provision if there is a reasonable reason, such as in the following cases:
2. 1. Illegal activity;
   2. Maintenance and inspection of information and communication facilities such as computers, equipment replacement and breakdown, disruption of communication, etc.
   3. Maintenance such as facilities for Service;
   4. Service unavailable due to power outage, failure of all facilities, or congestion of usage;
   5. Network failure across the country or region;
   6. When there is an unavoidable situation in which the Service cannot be provided due to Company circumstances; or
   7. Force majeure reasons such as natural disasters, national emergencies, regulations or restrictions under each country's laws/policies, etc.
3. The Company shall inform Users of planned changes to be made to its Service, along with the reasons for change and the date on which the change is to take effect, on the main (initial) service page prior to taking the change into effect. However, this is not the case if notification is not possible due to reasons beyond the Company's control.
4. The Company may revise, suspend, terminate, alter or modify part or the entirety of the Service, including various promotional events within the Service such as free commission events. Unless otherwise stipulated by the applicable laws, the Company shall not be held responsible for compensating Users for changes in such free services.
5. Users who do not agree with changes in the Company’s Services may indicate their refusal explicitly to the Company and terminate their Use Agreements.
6. The Company shall not be held liable for any problems arising from the change or interruption of this Service unless there is intention or negligence of the Company.

### 17. Provision of Information and Posting of Advertisements

1. The Company may provide a variety of information necessary for Service use to Users through notices or email. Users reserve the freedom to refuse to receive communications from the Company, except for those on transactions, inquiries, etc. required by the applicable laws.
2. The Company may place advertisements on the homepage and may send advertisements using email with the express consent of the User. If the User no longer wants to receive the above email even after providing consent, the User may refuse to receive the email at any time through the management function within the Service.
3. All advertisements, other services, links to other websites, and other materials provided outside the Services are provided by third parties. The Company does not have any rights or interests in relation to services or actions provided by third parties.

### 18. Termination of the Service

1. Users may terminate the Use Agreements they have entered with the Company at any time by withdrawing all their KAIA from the Service.
2. The Company may terminate the Use Agreements with Users for the reasons listed below. In such cases, the Company shall notify the User of the termination, and the cause(s) thereof, pursuant to Article 8. The Company shall allow the User to state its opinions on the alleged cause(s) of termination.
3. The Use Agreement shall expire the moment Company’s decision to terminate has been communicated to the User.
   1. Although the Company requested a User who is restricted from using the Service pursuant to Article 20 of these Terms of Use to correct by setting a considerable amount of time, if the User did not correct it within the requested period or the reason cause to the User cannot be corrected from objective perspective;
   2. Where the User has committed criminal acts, such as providing illegal programs, interrupting others’ services, hacking, distributing malicious programs, and attempting to access more information and resources than legally allowed;
   3. Where the User has attempted at, and/or succeeded in, interrupting Company’s Services;
4. Upon the termination of the Use Agreement, the User shall lose all the privileges and benefits it has gained from the use of Company’s Services, for which Company shall not have to compensate.
5. Notwithstanding Paragraph 3, the Company may elect to keep information on the User for a certain period of time to facilitate the processing and handling of the User’s objections or inquiries concerning Company’s decision to terminate the Use Agreement.
6. When the termination of the Use Agreement is completed, all information of the User will be deleted after thirty (30) days, except for cases where separate storage is specified in relevant laws and regulations.
7. Notwithstanding the preceding paragraph, in the event that it is terminated pursuant to paragraph 3 or if separate storage is specified in the terms and conditions or related laws for business processing such as payment for paid services, the User's information may be stored for a certain period of time.

### 19. (Refunds Etc.)

1. The User may request a refund for the payment made for using the Service provided by the Company within 7 days from payment date, unless:
   1. a normal service use is detected in the User’s account for at least 1 day
   2. an error or blockage on Orakl occurs due to reasons for which the User is responsible
   3. a restriction on use or a termination of contract is takes place due to a breach of the terms set forth herein by the User
   4. If it falls under the reasons for the restriction of withdrawal of subscription stipulated by other related laws such as the Act on the Consumer Protection in Electronic Commerce, Etc.
   5. If the User who applied for a refund did not directly purchase, such as the contents obtained free of charge through promotion, etc. or received as a gift from a third party
2. The Company may request payment information necessary for the refund process described in Paragraph 1. In such a case, the User must provide the requested information within the date set forth by the Company. Failing to do so may result in the cancellation of the refund process.
3. Refunds are to be made in the same payment method used by the User. In case it is not possible to make the refund in the same payment method, the refund may be made in a different method as set forth by the Company, which will be notified to the User in writing in advance.
4. The User is responsible for any damages following any non-compliance during the refund process by the User due to negligence or intentional disregard, even after the Company sufficiently informed the Users of the process in accordance with Paragraph 2, and the Company shall not be responsible.
5. If the User requests a refund for a payment made in KAIA, the amount of KAIA to be refunded shall be determined pursuant to Article 15.
6. In the event of a refund under the Paragraph 1, the procedures shall be in accordance with relevant laws and regulations such as the Act on the Consumer Protection in Electronic Commerce, etc.
7. To the extent permitted by applicable laws, the Company shall not be obligated to provide refunds if such a request for refunds falls outside the scope of liability defined in Article 21 or is based on the circumstances disclaimed by the Company under Article 22.

### 20. Restrictions on Use, Etc.

1. The Company gradually restrict the use of the Service by warning, suspension, permanent suspension of use and termination of the Use Agreement, such as in the following cases:
   1. Hacking and fraud incidents;
   2. Suspicion of impersonation;
   3. Request for service restrictions in accordance with the relevant laws and regulations of state agencies;
   4. Engaged or suspected of being involved in money laundering, unfair trade, or criminal activity;
   5. If a User violates the obligations of these Terms of Use, in case of any of the reasons set forth in Article 5(2) of these Terms of Use, in case of any breach of obligations set forth in Article 10 or 12 of these Terms of Use, or interferes with the normal operation of the service;
   6. Other reasons similar to each of the subparagraphs occur, or measures are required to prevent such occurrences;
2. If the use of the Service is restricted pursuant to the preceding paragraph, restrictions on the use of the Service may apply pursuant to Article 12
3. The Company may immediately revoke a User’s rights upon discovering that the User has violated law with acts including, but not limited to, misappropriation of third parties’ names and payment authority in violation of the Resident Registration Act; production of service-interrupting illegal computer programs in violation of the Copyrights Act and the Computer Program Protection Act; and illegal communications or hacking, distribution of malicious programs, illegal access, etc. in violation of the ICNA. Users whose rights are so revoked pursuant to this Paragraph shall be restricted to use some or all of the Service.
4. Users who are subject to restriction of service use or permanent suspension of use can cancel the restricted status only if they meet the cancellation conditions set by the Company.
5. If the Company restricts the use of the Service or terminates the Use Agreement pursuant to this Article, the Company notifies the User pursuant to Article 8.
6. Users can file an objection against measures such as restrictions on use according to the procedures set by the Company.

### 21. Limitation of Liability

1. We are not responsible or liable for any loss, damage, cost, or expense, whether direct or indirect (the “Losses”) incurred to the User if such Losses are due to the following reasons.
   1. If the Service cannot be provided due to natural disasters, equivalent national emergency or any other similar event with a cause outside of the Company’s control;
   2. If a use of the Service becomes impossible due to compliance with the de facto or legal administrative dispositions and/or orders of a government agency;
   3. If the service failure occurs due to a failure of the blockchain platform Kaia, data sources, data providers or a cause attributable to the User;
   4. If the data provided to the Users in connection with the POR service is inaccurate or not up-to-date due to reasons not attributable to the Company, including, without limitation, reasons such as API downtime or inaccurate data insertion by the original data provider;
   5. If the server fails due to instantaneous Service access increase, etc.
   6. When it is confirmed that the contents of information, data, and the reliability, accuracy and completeness of the information posted by the User in relation to the Service are altered or false.
   7. When there is no special provision in the relevant laws regarding the use of Services provided for free.
   8. When transactions are made between Users or between Users and third parties through Service.
   9. If the Losses are due to restriction or suspension of use according to these Terms of Use.
   10. if the Losses are due to technical defects that cannot be remedied with current technology available at the time of the Loss, force majeure, or events not attributable to the Company, including but not limited to power outages, fires, communication failures, DDoS attacks, IDC failures, or server downtime caused by a sudden surge in user access, or other similar events, which render the provision of Services impossible.
2. To the extent permitted by applicable laws, the Company does not make any direct or indirect agreements or guarantees for any matters not specified in these Terms of Use in relation to the Service.
3. The Company shall not be held responsible or liable for Users’ failure to reap the profits they expected from, or losses due to using, Company’s Services.
4. The User accepts and agrees that the sole and exclusive remedy available in connection with any liability arising from the use of the Services shall be limited to a full or partial refund of the fees paid. To the maximum extent permitted by applicable law, the Company shall not be liable for any Losses arising from or in connection with the Services, including but not limited to consequential, incidental, indirect, special, economic, or punitive damages, or any loss of business profits, goodwill, business interruption, computer malfunction or failure, loss of business information, or any other commercial or monetary Losses. In any event, the Company’s liability shall not exceed the actual amount of fees received from the User.

### 22. Disclaimer and Indemnification

1. ALL DATA, THIRD-PARTY INFORMATION, SOFTWARE, REFERENCE SITES, SERVICES, OR SOFTWARE MADE AVAILABLE IN CONJUNCTION WITH OR THROUGH OUR SERVICES, ETC., ARE PROVIDED ON AN “AS-IS,” “AS-AVAILABLE,” AND “WITH ALL FAULTS” BASIS AND, TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE COMPANY PROVIDES NO REPRESENTATION OR WARRANTY OF ANY KIND, IMPLIED OR OTHER WISE, REGARDING MERCHANTABILITY, ACCURACY, QUALITY, DURABILITY, RELIABILITY, PERFORMANCE, FITNESS FOR A PARTICULAR PURPOSE, INTELLECTUAL PROPERTY RIGHTS OR THE NON-INFRINGEMENT THEREOF, SMOOTH SERVICES, SERCURITY, PREVENTION OF DAMANGE OR LOSS OF DATA, ACCURACY OF INFORMATION, COMPLIANCE WITH RELEVANT LAWS, OR THE USE OR THE RESULTS OF THE USE OF THE SERVICES.
2. USERS EXPRESSLY AGREE THAT THE USE OF OUR SERVICES IS AT THEIR SOLE RISK. THE COMPANY DOES NOT WARRANT THAT THE DATA, SOFTWARE, FUNCTIONS, OR ANY OTHER INFORMATION OFFERED ON OR THROUGH OUR SERVICES WILL BE UNINTERRUPTED, UPDATED OR FREE OF ERRORS OF FACT OR OMISSIONS, VIRUSES OR OTHER HARMFUL COMPONENTS AND DOES NOT WARRANT THAT ANY OF THE FOREGOING WILL BE CORRECTED. IN PARTICULAR THE COMPANY DOES NOT WARRANT AND SHALL NOT BE RESPONSIBLE OR LIABLE FOR ANY OF THE LOSSES INCURRED BY THE USERS DUE TO THE INACCURACIES, ERRORS, OMISSIONS OR DELAYED UPDATES OF RAW DATA PROVIDED THROUGH THE API; USERS ACKNOWLEDGE THAT THE DATA MADE AVAILABLE THROUGH OUR SERVICES IS SOURCED FROM THIRD PARTIES AND MAY BE SUBJECT TO INACCURACIES OR DELAYS BEYOND THE CONTROL OF THE COMPANY. AND AGREE THAT THE COMPANY SHALL NOT BE RESPONSIBLE OR LIABLE FOR ANY INACCURACY, MISPRESENTATION OR DELAYS IN THE DATA PROVISION ON THE SERVICE UNLESS THE SAME IS DUE TO THE COMPANY’S WILFUL MISCONDUCT OR GROSS NEGLIGENCE.
3. USERS ACKNOWLEDGE, UNDERSTAND AND AGREE THAT IF USERS USE, ACCESS, DOWNLOAD, OR OTHERWISE OBTAIN INFORMATION, MATERIALS, OR DATA THROUGH OUR SERVICES, THE SAME SHALL BE AT THE USER’S OWN DISCRETION AND RISK OF THE USER AND THAT THE USER WILL BE SOLELY RESPONSIBLE FOR ANY DAMAGE TO THEIR PROPERTY OR LOSS OF ASSETS OR PROPERTY THAT RESULTS FROM USE OF SUCH MATERIAL OR DATA.
4. The provision of the Service shall not be construed as provision of any advice or recommendation by the Company.
5. The scope of indemnification to be provided by Company for the Losses suffered by Users due to Company’s fault shall only include the ordinary damages recognized under the Civil Act of the Republic of Korea. As for the Losses arising from specific circumstances the Company may be held liable only insofar as it can be ascertained that the Company knew of, or could have known of, such circumstances.
6. Notwithstanding Paragraph 1, the User shall be liable for part or all of his/her Losses in any of the following situations:
   1. Where the User failed to inform the Company in time, despite having known of the likelihood or fact of the Losses;
   2. Where the User has disclosed, whether by deliberate act or negligence, its information, including its account and details of transactions, to a third party;
   3. Where the User is otherwise attributable for the Losses, whether by deliberate act or negligence;
7. The Company shall not be held liable for the Losses that Users suffer through if there exists no fault or negligence of the Company. Further the Company shall not be liable for any Losses resulting from lost profits or revenue or any special, incidental, or consequential damages arising out of the use of the Service, unless such Losses are due to the Company’s willful misconduct or gross negligence.
8. Where the information provided by a User is inaccurate or untrue, the Company may suspend or revoke the User’s rights related to the Service under these Terms of Use, and may file claims for damages against the User should such false information have caused Losses to the Company.
9. Any User whose deliberate acts or omission, willful misconduct or negligence interrupts Company’s systems and operations or violates the law, these Terms of Use, or the good and fine customs of society, and thereby causes Losses to the Company, shall be held liable to such Losses and shall indemnify the Company its directors, officers, employees, agents, representatives or agents for any and all of the Losses.
10. The Company further disclaims and clarifies the following.
    1. The token price data displayed on the Service is sourced from decentralized exchanges (DEXs) and is provided for informational purposes only. It does not constitute financial advice, an endorsement, or an offer to buy or sell any digital asset. DEX token prices may be subject to significant volatility, low liquidity, and sudden price fluctuations due to market dynamics. While Orakl Network may provide Volume-Weighted Average Price (VWAP) data where applicable, VWAP is limited in effectiveness and reliability when derived from a single data source or in conditions of low trading volume. In such cases, the displayed price data may not accurately reflect broader market conditions or fair value. Users and developers are strongly encouraged to implement on-chain Time-Weighted Average Price (TWAP) mechanisms within smart contracts and applications to mitigate risks associated with sudden price movements or market manipulation in illiquid markets.
    2. By accessing or using the Service, you acknowledge and agree that the token price data is provided "as is" and "as available," without any warranties or representations of any kind, whether express or implied. Orakl Network makes no representations or warranties regarding the accuracy, timeliness, completeness, reliability or suitability of the token price data for any purpose. You are solely responsible for any decisions or actions taken based on the information and data provided through the Services. The Company shall not be liable for any loss or damage arising from your use of, or reliance on, such data. You are strongly advised to exercise caution and conduct independent verification before relying on token price data for any financial, contractual, or other decision-making purposes.
    3. You further acknowledge and understand that token prices, particularly those derived from decentralized exchanges, are subject to highly volatility and may fluctuate significantly over short periods. You understand and accept that low transaction volume, limited liquidity, or irregular trading activity may result in abrupt price fluctuations or distorted pricing data, which may not accurately reflect fair market value. In light of the foregoing, you acknowledge and agree that, in markets with low activity or illiquidity, or where price data from centralized exchanges (CEXs) is not utilized, the displayed token price may be incomplete, inaccurate, misleading, or otherwise distorted, and that the Company shall not be liable for any losses, damages, or liabilities arising in connection with, or resulting from, reliance on such data.

### 23. Applicable Law and Jurisdiction

1. The laws of the Republic of Korea shall be the proper law governing this Terms and any disputes between Company and Users.
2. The court of the jurisdiction in which the User is permanently located, at the time of pressing the lawsuit, shall be the competent court presiding over the litigation between Company and a given User. Where the User lacks a permanent address and jurisdiction, the district court presiding over the jurisdiction in which the Company is temporarily located shall oversee the litigation. Where the User lacks a definite permanent or temporary address at the time of the lawsuit, the competent court shall be decided according to the Civil Litigation Act.
3. Notwithstanding the foregoing, any litigation between a User with a foreign permanent or temporary address and the Company shall be presided over by the Seoul Central District Court in the Republic of Korea.

These Terms of Use is effective as of September 4, 2025.


