# Oracle with Custom Chaincode

**Example:**

**Oracle id:** 64e8bc2c4708667b390d8694

**Weather API details:**

```
https://rapidapi.com/weatherapi/api/weatherapi-com

Oracle config:
METHOD: Get
URL: https://weatherapi-com.p.rapidapi.com/current.json

Params Type: Query
Authentication Method: Custom
Authentication Headers: 
X-RapidAPI-Key: **************************
Custom Headers:
X-RapidAPI-Host: weatherapi-com.p.rapidapi.com
```

**Scheduler config:**

```
Cron: * * * * *
Oracle Request Params: 
q: Texas
App: <Custom Chaincode>
Function name: <ContractName:CustomChaincodeName> 
(Eg: SmartContract:OracleScheduleHandler)
```

***

#### <mark style="color:blue;">On Demand Request:</mark>

To get external data (oracle data) from a custom chaincode, users must perform a cross-chaincode call to Spydra’s oracle chaincode which acts as an interface to the oracle services that Spydra offer.

* Spydra’s oracle chaincode is deployed with a constant name `oracle.`\
  If you have created multiple channels in your network and have created oracles for those channels as well, then the first deployed oracle chaincode's name is `oracle` , the deployed oracle chaincode's name is `oracle1` and so on.\
  \
  The chaincode name of a particular oracle can always be found on the oracle descriptions or list page. You can reach the oracle listing page by clicking Oracle tab in the Network page.
* It has a <mark style="color:orange;">`OracleRequest`</mark> function that accepts the following json data as input

```json
{
  oracleSetId: string; // The oracle id found on UI
  params: any; // query/path/body params of the defined oracle - this can be an object or string or empty
}

```

* To make a cross chaincode call from HLF chaincode, <mark style="color:orange;">`stub.InvokeChaincode`</mark> api can be used. <mark style="color:orange;">`stub.InvokeChaincode`</mark> accepts 3 parameters:&#x20;

1\. chaincodeName (string)

2\. args (\[]\[]byte or Array.\<Array.\<byte>>  or array of array of bytes)

3.channel (string)

* The first element of args must contain the **function name** of the calling chaincode.
* Further elements of args can contain the actual arguments of the function.

HLF API doc reference:\
**Golang:** [https://pkg.go.dev/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStubInterface<br>](https://pkg.go.dev/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStubInterface)**Node.js:** [https://hyperledger.github.io/fabric-chaincode-node/main/api/fabric-shim.ChaincodeStub.html#invokeChaincode\_\_anchor<br>](https://hyperledger.github.io/fabric-chaincode-node/main/api/fabric-shim.ChaincodeStub.html#invokeChaincode__anchor)

Example: To request external data from above defined oracle

```go
// ToChaincodeArgs converts string args to []byte args
func ToChaincodeArgs(args ...string) [][]byte {
    bargs := make([][]byte, len(args))
    for i, arg := range args {
        bargs[i] = []byte(arg)
    }
    return bargs
}


// My chaincode function
func (s *SmartContract) MyCustomFunction(ctx contractapi.TransactionContextInterface) (output string, err error) {
    stub := ctx.GetStub()
    txId := stub.GetTxID()


    var oracleRequestParams string = `{"oracleSetId":"64e8bc2c4708667b390d8694","params":{"q":"Texas"}}`
    chaincodeArgs := util.ToChaincodeArgs("OracleContract:OracleRequest", oracleRequestParams)


    // Request external data (oracle)
    response := stub.InvokeChaincode("oracle", chaincodeArgs, "") // channel parameter can be left empty


    fmt.Println("ORACLE RESPONSE: ", response.Status, response.Message, string(response.Payload))


    if response.Status != 200 {
        err = fmt.Errorf(string(response.Message))
        return
    }


    dataBytes := response.GetPayload()


    // Save to blockchain state
    err = stub.PutState(txId, dataBytes)
    if err != nil {
        fmt.Println(err)
        return
    }


    output = string(dataBytes)
    return
}
```

***

#### <mark style="color:blue;">Oracle Scheduler</mark>

A scheduled oracle retrieves data from the API configured in the oracle definition and calls the chaincode function as configured in the APPLICATION section of the oracle scheduler config.

The scheduler calls the chaincode function with the following argument:

```json
{
  oracleCronId: string; // The internal oracle cron scheduler id
  refId: string; // Reference id for this scheduled transaction
  data: any; // Response given by API configured in oracle
}
```

Example: To receive data from the oracle scheduler

```go
type OracleCallbackArgs struct {
    OracleCronId string      `json:"oracleCronId"`
    RefId        string      `json:"refId"`
    Data         interface{} `json:"data,omitempty" metadata:",optional"`
}


func (s *SmartContract) OracleScheduleHandler(ctx contractapi.TransactionContextInterface, input OracleCallbackArgs) (err error) {
    stub := ctx.GetStub()
    txId := stub.GetTxID()


    var minput []byte
    minput, err = json.Marshal(input)
    if err != nil {
        fmt.Println(err)
        return
    }


    err = stub.PutState(txId, minput)
    if err != nil {
        fmt.Println(err)
        return
    }


    return
}
```
