ethereumsolidityhardhatchainlink

Testing Chainlink API calls using Hardhat


I am having trouble testing Chainlink API calls locally. I have a contract which calls my API consumer contract to make an API call. However, when I try to do that, the MockOracle (mocked oracle for local testing, from chainlink) contract reverts (VM exception) saying "Must use whitelisted functions". I am making an API call for a bytes32 get request.

This is the function modifier (inside of LinkTokenReceiver) where the MockOracle reverts (it gets called by the MockOracle when receiving LINK tokens):

/**
   * @dev Reverts if the given data does not begin with the `oracleRequest` function selector
   * @param _data The data payload of the request
   */
  modifier permittedFunctionsForLINK(bytes memory _data) {
    bytes4 funcSelector;
    assembly {
      // solhint-disable-next-line avoid-low-level-calls
      funcSelector := mload(add(_data, 32))
    }
    require(funcSelector == ORACLE_REQUEST_SELECTOR, "Must use whitelisted functions");
    _;
  }

The ApiConsumer is properly funded, and the LINK token is a local deployment of the chainlink Token. So, what am I doing wrong? Or what is the best way to test Chainlink API calls (bytes32 get request) locally using hardhat?


Solution

  • In Chainlink oracle workflow, consumers are basically supposed to send a request to the off-chain oracle node so that the oracle node can fetch data from the API specified by consumers. In the workflow, request sent by user must be caught by off-chain oracle node.

    What you are doing here is to send your request to smart contract oracle and the oracle save your request into event log oracleRequest so that it could be caught by off-chain oracle.

    Your problem here is as suggested by modifier permittedFunctionForLINK, the function selector is not oracleRequest so that off-chain oracle cannot recognize the request.

    I am guessing you are currently using the oracle.sol and ChainlinkClient.sol in version v0.6. In version v0.6, AFAIK, ChainlinkClient doesn't not help users to add function selector oracleRequest in the users' Chainlink request, which means you will get the error if you doesn't manually add the function selector in your request. In v0.7, ChainlinkClient helps you add the selector in the request. Just check the function sendChainlinkRequestTo in ChainlinkClient v0.6 and ChainlinkClient v0.7 by yourself.

    Solutions:

    1. Use the v0.7 ChainlinkClient and operator.sol(smart contract oracle.sol is renamed as operator.sol in v0.7) for your test. The document can be found here.
    2. There is a repo called hardhat-starter-kit in Chainlink official github, there are sample codes you can try. Or you can directly use starterkit to test AnyApi and any other services.