1

I am trying to fetch data from an api which gives multiple response in single call and I am doing this using chainlink external API calls.

In my smart contract i have use array of struct to store requested data after request fulfil by Operator contract. I had also created my own job spec [TOML File] by running node locally on my system.

Now my error occur inside job spec file when i request for data.

For better understanding i have provided my smart contract code and job code also there is a screen shot of error that occur when execution while fetch populating fetch data into struct formate of fulfillMultipleParameters(bytes32 requestId,Trade[] memory _prices)

Screen shot of error

enter image description here

Node Operator Job Spec TOML File

schemaVersion = 1
name = "Multiple_Array_of_Struct_Datas_1"
forwardingAllowed = true
maxTaskDuration = "0s"
contractAddress = "0x2D470Df5823edefe6941F8F737660661e47f62af"
minContractPaymentLinkJuels = "0"
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_log -> decode_cbor


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

fetch [type="http" method=GET url="$(decode_cbor.url)" allowunrestrictednetworkaccess="true"]


decode_cbor -> fetch



path1_parse [type="jsonparse" path="$(decode_cbor.path1)" data="$(fetch)" ]

path2_parse [type="jsonparse" path="$(decode_cbor.path2)" data="$(fetch)"]

path3_parse [type="jsonparse" path="$(decode_cbor.path3)" data="$(fetch)"]

path4_parse [type="jsonparse" path="$(decode_cbor.path4)" data="$(fetch)"]

path5_parse [type="jsonparse" path="$(decode_cbor.path5)" data="$(fetch)"]

fetch -> path1_parse
fetch -> path2_parse
fetch -> path3_parse
fetch -> path4_parse
fetch -> path5_parse

path5_parse -> encode_mwr
path4_parse -> encode_mwr
path3_parse -> encode_mwr
path2_parse -> encode_mwr
path1_parse -> encode_mwr


encode_mwr [type="ethabiencode"
                abi="(bytes32 requestId, Trade[] _prices)"
                data="{\\"requestId\\": $(decode_log.requestId), \\"_prices\\": [[ $(path1_parse)], [$(path2_parse)], [$(path3_parse)], [$(path4_parse)], [$(path5_parse)]]}"
                ]


encode_tx  [type="ethabiencode"
                abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)"
                data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\":   $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_mwr)}"
                ]
    submit_tx  [type="ethtx" to="0x2D470Df5823edefe6941F8F737660661e47f62af" data="$(encode_tx)" from="[\\"0x761Cd84957ecD0344E6C01a02A7cAe479D07B838\\"]"]
    encode_mwr -> encode_tx -> submit_tx
"""

Smart Contract Code

pragma solidity ^0.8.7;

import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
import "@chainlink/contracts/src/v0.8/ConfirmedOwner.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

/**
 * Request testnet LINK and ETH here: https://faucets.chain.link/
 * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: https://docs.chain.link/docs/link-token-contracts/
 */

/**
 * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY.
 * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.
 * DO NOT USE THIS CODE IN PRODUCTION.
 */

contract MultiWordConsumer is ChainlinkClient, ConfirmedOwner {
    using Chainlink for Chainlink.Request;

    struct Trade{
        string price;
    }

    bytes32 private jobId;
    uint256 private fee;

    // multiple params returned in a single oracle response
    Trade[] public trades;
   

    event RequestMultipleFulfilled(
        bytes32 indexed requestId,
        Trade[] indexed prices
    );

    /**
     * @notice Initialize the link token and target oracle
     * @dev The oracle address must be an Operator contract for multiword response
     *
     *
     * Sepolia Testnet details:
     * Link Token: 0x779877A7B0D9E8603169DdbD7836e478b4624789
     * Oracle: 0x6090149792dAAeE9D1D568c9f9a6F6B46AA29eFD (Chainlink DevRel)
     * jobId: 53f9755920cd451a8fe46f5087468395
     *
     */
    constructor() ConfirmedOwner(msg.sender) {
        setChainlinkToken(0x779877A7B0D9E8603169DdbD7836e478b4624789); 
        setChainlinkOracle(0x2D470Df5823edefe6941F8F737660661e47f62af); // Operator Contract Address
        jobId = "3464b5f4c3f74b66a22f881506d2aae5"; //3464b5f4-c3f7-4b66-a22f-881506d2aae5
        fee = (1 * LINK_DIVISIBILITY) / 10; // 0,1  10**18 (Varies by network and job)
    }

    /**
     * @notice Request mutiple parameters from the oracle in a single transaction
     */
    function requestMultipleParameters() public {
        Chainlink.Request memory req = buildChainlinkRequest(
            jobId,
            address(this),
            this.fulfillMultipleParameters.selector
        );
        req.add(
            "url",
            "https://api3.binance.com/api/v3/trades?symbol=BTCUSDT&limit=5"
        );

        for(uint i=0; i<5; i++){
        string memory strindex = Strings.toString(i);
        uint index = i + 1;
        string memory pathindex = Strings.toString(index);
        req.add(string.concat("path",pathindex), string.concat(strindex,",price"));

        }
        // req.add("path2", "1,price");
        // req.add("path3", "2,price");
        // req.add("path4", "3,price");
        // req.add("path5", "4,price");
        sendChainlinkRequest(req, fee); // MWR API.
    }

    /**
     * @notice Fulfillment function for multiple parameters in a single request
     * @dev This is called by the oracle. recordChainlinkFulfillment must be used.
     */
    function fulfillMultipleParameters(
        bytes32 requestId,
        Trade[] memory _prices
    ) public recordChainlinkFulfillment(requestId) {
        emit RequestMultipleFulfilled(
            requestId,
            _prices
        );

        for(uint i = 0; i< _prices.length; i++){
            trades.push(_prices[i]);
        }

    }

    function viewprice() public view returns(Trade[] memory ){
       
        return trades;
    }

    /**
     * Allow withdraw of Link tokens from the contract
     */
    function withdrawLink() public onlyOwner {
        LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
        require(
            link.transfer(msg.sender, link.balanceOf(address(this))),
            "Unable to transfer"
        );
    }
}```



 

2 Answers 2

1

Can you try changing bytes32 to bytes in encode_tx and see if it works?

0
0

You have to create separate array of each field in fulfillMultipleParameters() and then push it inside array of struct. As Job spec does not support struct type as an argument.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.