Getting individual array elements from the data returned by a chainlink external adapter

Viewed 110

In the job I'm adding for my external adapter, I'm looking to get results for the first 3 elements in the Results array one at a time.(see the data returned from my external adapter below)

So I'm adding "position" to my chainlink request in the consumer contract and wanting to use that in the jsonparse like below, rather than pass it to the external adapter. However, I get this error JSONParse task error: $(decode_cbor.position) is not a valid array index

parse        [type=jsonparse path="data,MRData,RaceTable,Races,0,Results,$(decode_cbor.position),number" data="$(fetch)"]```

in my consumer contract

Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
request.add("position", "1");

The data returned from the external adapter looks like this.

{
    "MRData": {
        "xmlns": "http://ergast.com/mrd/1.4",
        "series": "f1",
        "url": "http://ergast.com/api/f1/current/last/results.json",
        "limit": "30",
        "offset": "0",
        "total": "20",
                
        "RaceTable": {
            "season": "2021",
            "round": "17",
        
          "Races": [{
                "season": "2021",
                "round": "17",
                "url": "http://en.wikipedia.org/wiki/2021_United_States_Grand_Prix",
                "raceName": "United States Grand Prix",
                "Circuit": {
                    "circuitId": "americas",
                    "url": "http://en.wikipedia.org/wiki/Circuit_of_the_Americas",
                    "circuitName": "Circuit of the Americas",
                    "Location": {
                        "lat": "30.1328",
                        "long": "-97.6411",
                        "locality": "Austin",
                        "country": "USA"
                    }
                },
                "date": "2021-10-24",
                "time": "19:00:00Z",
        
                "Results": [{
                    "number": "33",
                    "position": "1",
                    "positionText": "1",
                    "points": "25",
                    "Driver": {
                        "driverId": "max_verstappen",
                        "permanentNumber": "33",
                        "code": "VER",
                        "url": "http://en.wikipedia.org/wiki/Max_Verstappen",
                        "givenName": "Max",
                        "familyName": "Verstappen",
                        "dateOfBirth": "1997-09-30",
                        "nationality": "Dutch"
                    },.....

The full results can be found here. http://ergast.com/api/f1/current/last/results.json

Should I be able to do something like this? Is there a better way to go about this? Should I edit the adapter instead?

schemaVersion = 1
name = "f1latestresults2"
contractAddress = "0x765aCc258f3a7b2D8d103D1A9310fc51b07D5425"
maxTaskDuration = "0s"
observationSource = """
    decode_log   [type=ethabidecodelog
                  abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)"
                  data="$(jobRun.logData)"
                  topics="$(jobRun.logTopics)"]

    decode_cbor  [type=cborparse data="$(decode_log.data)"]

    fetch        [type=bridge name="raceresults" requestData="{\\"id\\":$(jobSpec.externalJobID),\\"data\\":{\\"position\\":\\"0\\"}}"]
    

    parse        [type=jsonparse path="data,MRData,RaceTable,Races,0,Results,$(decode_cbor.position),number" data="$(fetch)"]

    encode_data  [type=ethabiencode abi="(uint256 value)" data="{ \\"value\\": $(parse) }"]
    encode_tx    [type=ethabiencode
                  abi="fulfillOracleRequest(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes32 data)"
                  data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}"
                 ]
    submit_tx    [type=ethtx to="0x765aCc258f3a7b2D8d103D1A9310fc51b07D5425" data="$(encode_tx)"]

    decode_log -> decode_cbor -> fetch -> parse -> encode_data -> encode_tx -> submit_tx
"""
externalJobID = "cfa059b4-a31d-4c30-99e4-3a2fd4c57739"
1 Answers

The syntax you are using looks correct to me, so I'm not 100% sure if the TOML jobs can support having a parameter like that within a string yet?

If the rest of the JSON path is static, suggest just having it as a built up string in your consuming contract, and just sending it as a full string in the request, then using that in your TOML spec, similar to the example in the docs

req.add("path", "data,MRData,RaceTable,Races,0,Results,0");

Then in your TOML job spec:

parse        [type=jsonparse path="$(decode_cbor.path)" data="$(fetch)"]
Related