# JavaScript API

## Introduction

### Javascript client for reading feeding price data of Banksea Oracle

Banksea NFT Price Oracle aims at delivering price prediction and risk assessment to Banksea Protocol as well as the larger NFT ecosystem. Price oracle use cases：

* NFT Sale: Buyers can use NFT price oracle to inform their NFT purchase
* NFT Collateral: Protocols or lenders can use the price prediction and risk assessment to determine risk of the loan.
* NFT Trading: Users can monitor the price prediction and risk assessment fluctuations to make trading decisions.

## Installation

```bash
yarn add @banksea-finance/oracle-client 
# or use npm: 
npm install @banksea-finance/oracle-client --save
```

## Example usage

### 1. Build a client

The library mainly exported a class named `BankseaOracleClient`, which providers a serials of methods for users to interact with our `Oracle` program deployed on Solana network.

So the first step of all, you need to build a `BankseaOracleClient` instance:

```typescript
import { BankseaOracleClient } from '@banksea-finance/oracle-client'
import { Cluster } from '@solana/web3.js'

const cluster: Cluster = 'devnet'
const endpoint: string = 'https://mango.devnet.rpcpool.com/'
const keypair = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(fs.readFileSync('./env/id.json').toString('utf-8'))))
const wallet = new Wallet(keypair)

const oracleClient: BankseaOracleClient = new BankseaOracleClient(cluster, { endpoint, wallet })
```

**NOTE**:

* The code above contains the calling of `fs`, which is the Node.js only module, so you can NOT use this in browser environment. If you are developing in browser environment, consider using adapter provided by external wallet(usually a browser extension such as Phantom, Solflare, etc.).
* The `endpoint` field in the second argument `opts` is not necessary. If not provided, it would be set to `clusterApiUrl(cluster)`, that is the public RPC URL provided by Solana. But you need to note that the performance of public RPC can sometimes be a bit bad.
* In the second argument of the constructor, `opts`, there is another field: `oracle`. The field is in type of `PublicKey`(from `@solana/web3.js`), and means **the address of oracle**.\
  In normal, you don't need to specify this argument, because the library has configured the default oracle address for each Solana cluster(if the Oracle program has been deployed on it by Banksea). But we also allow advanced users to create a new custom Oracle on Solana network, in which case you must specify the `oracle` argument to find the one you want to interact with.

### 2. List all subscribable collections

Before subscribing for feeding, you need to know "what can you subscribe and how can you subscribe".

In our design, the unit and minimum unit to subscribe is the `collection`. And all subscribable collections are configured as `whitelist`.

`whitelist` is an account in Banksea Oracle Program. Each `whitelist` mainly contains:

* oracle: the oracle address which the whitelist belongs to;
* code: the unique identifier of a whitelist, which is usually the name of collection;
* unit: the unit of feed price data, maybe 'SOL' or 'ETH';
* decimals: the decimals of feed price data. For example: if the `decimals` is 9 and the feed price data you read is `375000000` and the unit is `SOL`, it means that the real(human-readable) price is `375000000 * 10^-9 = 0.375 SOL`

You can use the `listWhitelists` method to read all whitelist, that is, all collections that can be subscribed to:

#### Typescript version

```typescript
import { WhitelistAccount } from '@banksea-finance/oracle-client'

const whitelists: WhitelistAccount[] = await oracleClient.listWhitelists()
```

#### Javascript version

```javascript
const whitelists = await oracleClient.listWhitelists()
```

### 3. Subscribe to the collection

Before subscribing, you need to confirm the arguments following:

* feedCount: the total number of times to feed. Will reduce 1 ever when feeding, and will stop feeding after reducing to 0;
* feedInterval: the interval of the price feeding cycle, that is, how often the price feeding will be carried out. (In unit of second)
* feedNodeCount: Required minimum feeding node count.\
  If the actual number of nodes that complete the feeding in one cycle is less that the `feedNodeCount`, the aggregating in that cycle will fail, which means there will be no price data in that cycle.\
  **NOTE**: this value need to be less than or equal to `nodeCount` of collection config
* collectionTaskKeypair: The keypair of the `collectionTask` to create(A subscribing is essentially creating a `CollectionTask` account). You can manually specify a keypair when subscribing. If not, a random one will be automatically generated internally.

Then you can call the `subscribe` method:

```typescript
import BN from 'bn.js' // or: import { BN } from '@project-serum/anchor'

const feedCount = new BN(10)
const feedInterval = new BN(3600) // 3600 seconds
const feedNodeCount = new BN(3)   // Require minimum to 3 nodes to feed in one cycle

const whitelists = await oracleClient.listWhitelists()
const whitelistPubkey = whitelists[0].pubkey          // Just choose one you like to subscribe
const collectionTaskKeypair = Keypair.generate()      // Use a random one. 

await oracleClient.subscribe({
  feedCount,
  feedInterval,
  feedNodeCount,
  whitelistPubkey,
  collectionTaskKeypair // this argument is optional
})
```

### 4. Update config of subscription task

You can also use the `updateSubscription` method to update the subscription config.

* You can just set the `feedCount` to `0` to cancel the subscribing, and set it to a positive number to restart.
* When updating, you don't need to specify the argument `collectionTaskKeypair` & `whitelistPubkey` anymore, but you must specify the `collectionTaskPubkey` argument additionally to tell the library which one task to update.
* When updating, you just need to pass the arguments which you want to update. The missing arguments will be treated as *no need to update*

Here is the example of updating:

```typescript
const feedInterval = new BN(7200)
const collectionTaskPubkey = collectionTaskKeypair.publicKey

await oracleClient.updateSubscription({
  feedInterval,
  collectionTaskPubkey
})
```

In the example, only the `feedInterval` will be updated, and any other configs will not be changed.

### 5. Query all tasks you subscribed to

You can use the `listTasksBySubscriber` method to query all tasks subscribed to by a particular subscriber:

```typescript
const tasksBySubscriber = await oracleClient.listTasksBySubscriber(subscriber)
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://banksea-finance.gitbook.io/oracle/user-guide/javascript-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
