Chainlink v0.8 API Large Responses

Viewed 302

I am following the Large Responses Chainlink tutorial and am receiving an error when trying to call the requestOracleData() function. Everything works fine when using v0.6, but I need to use v0.8 in order to receive large responses.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

/**
 * @title MyContract is an example contract which requests data from
 * the Chainlink network
 * @dev This contract is designed to work on multiple networks, including
 * local test networks
 */
contract MyContract is ChainlinkClient, ERC721 {
    using Chainlink for Chainlink.Request;

    // address constant ORACLE = 0xF405B99ACa8578B9eb989ee2b69D518aaDb90c1F;
    // bytes32 constant JOB_ID = bytes32("7c4b968028f74b2eabd7d428f03ba45c");

    address constant RINKEBY_ORACLE =
        0x3A56aE4a2831C3d3514b5D7Af5578E45eBDb7a40;
    bytes32 constant RINKEBY_JOB_ID =
        bytes32("187bb80e5ee74a139734cac7475f3c6e");

    uint256 constant FEE = 0.1 * 10**18;

    bytes32 internal keyHash;
    uint256 public fee;
    uint256 public tokenCounter;

    // bytes public data;

    bytes32 public data;
    string public image_url;

    struct Clip {
        string name;
        string url;
    }

    Clip[] public clips;

    mapping(bytes32 => string) public requestIdToClipName;
    mapping(bytes32 => address) public requestIdToSender;
    mapping(bytes32 => string) public requestIdToTokenURI;
    event requestedCollectible(bytes32 indexed requestId);

    mapping(bytes32 => uint256) public requestToTokenId;
    mapping(uint256 => string) public tokenIdToName;
    mapping(uint256 => string) public tokenIdToImgUrl;

    constructor(address _link) public ERC721("Tests", "TST") {
        if (_link == address(0)) {
            setPublicChainlinkToken();
        } else {
            setChainlinkToken(_link);
        }
        setChainlinkOracle(0x3A56aE4a2831C3d3514b5D7Af5578E45eBDb7a40);
        tokenCounter = 0;
    }


    function getChainlinkToken() public view returns (address) {
        return chainlinkTokenAddress();
    }

    function createRequestTo(
        string memory _url,
        string memory _path,
        string memory clipName
    ) public returns (bytes32 requestId) {
        Chainlink.Request memory req = buildChainlinkRequest(
            RINKEBY_JOB_ID,
            address(this),
            this.fulfill.selector
        );
        req.add("get", _url);
        req.add("path", _path);
        
        requestOracleData(req, FEE);

        requestId = sendChainlinkRequestTo(RINKEBY_ORACLE, req, FEE);
        requestIdToClipName[requestId] = clipName;
        requestIdToSender[requestId] = msg.sender;
        emit requestedCollectible(requestId);
        return requestId;
    }

    function fulfill(bytes32 _requestId, bytes32 _data)
        public
        recordChainlinkFulfillment(_requestId)
    {
        address nftOwner = requestIdToSender[_requestId];
        string memory name = requestIdToClipName[_requestId];
        uint256 newItemId = clips.length;

        data = _data;
        image_url = bytes32ToString(data);

        clips.push(Clip(name, image_url));

        _safeMint(nftOwner, newItemId);

        tokenIdToName[newItemId] = name;
        tokenIdToImgUrl[newItemId] = image_url;
    }


    function getNumberOfClips() public view returns (uint256) {
        return clips.length;
    }

    /**
     * @notice Allows the owner to withdraw any LINK balance on the contract
     */
    function withdrawLink() public {
        LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
        require(
            link.transfer(msg.sender, link.balanceOf(address(this))),
            "Unable to transfer"
        );
    }

    /**
     * @notice Call this method if no response is received within 5 minutes
     * @param _requestId The ID that was generated for the request to cancel
     * @param _payment The payment specified for the request to cancel
     * @param _callbackFunctionId The bytes4 callback function ID specified for
     * the request to cancel
     * @param _expiration The expiration generated for the request to cancel
     */
    function cancelRequest(
        bytes32 _requestId,
        uint256 _payment,
        bytes4 _callbackFunctionId,
        uint256 _expiration
    ) public {
        cancelChainlinkRequest(
            _requestId,
            _payment,
            _callbackFunctionId,
            _expiration
        );
    }

    function bytes32ToString(bytes32 _bytes32)
        public
        pure
        returns (string memory)
    {
        uint8 i = 0;
        while (i < 32 && _bytes32[i] != 0) {
            i++;
        }
        bytes memory bytesArray = new bytes(i);
        for (i = 0; i < 32 && _bytes32[i] != 0; i++) {
            bytesArray[i] = _bytes32[i];
        }
        return string(bytesArray);
    }
}

Here is the error I am getting:

Running 'scripts/request_data.py::main'...
  File "brownie/_cli/run.py", line 49, in main
    return_value, frame = run(
  File "brownie/project/scripts.py", line 103, in run
    return_value = f_locals[method_name](*args, **kwargs)
  File "./scripts/request_data.py", line 18, in main
    apicall = my_contract.createRequestTo(URL, PATH, "test", {"from": dev})
  File "brownie/network/contract.py", line 1693, in __call__
    return self.transact(*args)
  File "brownie/network/contract.py", line 1566, in transact
    return tx["from"].transfer(
  File "brownie/network/account.py", line 642, in transfer
    receipt, exc = self._make_transaction(
  File "brownie/network/account.py", line 725, in _make_transaction
    raise VirtualMachineError(e) from None
  File "brownie/exceptions.py", line 121, in __init__
    raise ValueError(str(exc)) from None
ValueError: Gas estimation failed: 'execution reverted: Must use whitelisted functions'. This transaction will likely revert. If you wish to broadcast, you must set the gas limit manually.

Note: this error doesn't occur when I comment out the requestOracleData() function.

1 Answers

It is due to the fact that the node operator you are using on Rinkeby isn't set up to handle large requests and is most likely using the Oracle.sol code as their oracle contract, which doesn't accept the requestOracleData() method.

You can either switch to Kovan and use the node given in the docs, search for a different but compatible node on market.link, or host your own node on Rinkeby which is compatible with this job.

Related