Search code examples
httpethereumsoliditysmartcontractschainlink

Ethereum Chainlink HTTP Get not pinging my HTTP endpoint


I am attempting to have my Ethereum smart contract connect to an external HTTP endpoint using Chainlink. Following along with Chainlink's documentation (https://docs.chain.link/docs/advanced-tutorial/) I deployed this contract onto the Rinkeby testnet.

pragma solidity ^0.8.7;

import "github.com/smartcontractkit/chainlink/blob/develop/contracts/src/v0.8/ChainlinkClient.sol";

// MyContract inherits the ChainlinkClient contract to gain the
// functionality of creating Chainlink requests


contract getHTTP is ChainlinkClient {
  using Chainlink for Chainlink.Request;

  bytes32 private thisDoesNotWork;
  address private owner;
  address private ORACLE_ADDRESS = 0x718Cc73722a2621De5F2f0Cb47A5180875f62D60;
  bytes32 private JOBID = stringToBytes32("86b489ec4d84439c96181a8df7b22223");
  string private url = "<myHTTPAddressAsString>"; 

// This endpoint URL is hard coded in my contract, and stored as a string (as in the example code). 
// I control it and can have it reply with whatever I want, which might be an issue, returning data in a format that the oracle rejects

  uint256 constant private ORACLE_PAYMENT = 100000000000000000;

  constructor() public {
    // Set the address for the LINK token for the network
    setPublicChainlinkToken();
    owner = msg.sender;
  }

  function requestBytes() 
    public
    onlyOwner
  {
    Chainlink.Request memory req = buildChainlinkRequest(JOBID, address(this), this.fulfill.selector);
    req.add("get", url);
    sendChainlinkRequestTo(ORACLE_ADDRESS, req, ORACLE_PAYMENT);
  }

  function fulfill(bytes32 _requestId, bytes32 recVal)
    public
    recordChainlinkFulfillment(_requestId)
  {
    thisDoesNotWork = recVal;
  }
  function cancelRequest(
    bytes32 _requestId,
    uint256 _payment,
    bytes4 _callbackFunctionId,
    uint256 _expiration
  )
    public
    onlyOwner
  {
    cancelChainlinkRequest(_requestId, _payment, _callbackFunctionId, _expiration);
  }

  
  // withdrawLink allows the owner to withdraw any extra LINK on the contract
  function withdrawLink()
    public
    onlyOwner
  {
    LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
    require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer");
  }
  
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }
  
   // A helper funciton to make the string a bytes32
  function stringToBytes32(string memory source) private pure returns (bytes32 result) {
    bytes memory tempEmptyStringTest = bytes(source);
    if (tempEmptyStringTest.length == 0) {
      return 0x0;
    }
    assembly { // solhint-disable-line no-inline-assembly
      result := mload(add(source, 32))
    }
  }
}

I found a node on the Chainlink market (https://market.link/jobs/529c7194-c665-4b30-8d25-5321ea49d9cc) that is currently active on rinkeby (according to Etherscan it has been active within the past 3 days and presumably still working).

I deploy the contract and fund the contract with LINK. I call the requestBytes() function through remix and everything works as expected. Metamask pays the gas, the LINK is removed from my contract, I get a transaction hash, and no errors.

However, my endpoint never logs a request attempt, the oracle never lists a transaction on its Etherscan page, and my data is not present.

I have attempted to use other jobs from the Chainlink market with similar outcomes.

I have also attempted to use other HTTP endpoints, like the ones from the Chainlink examples, with similar outcomes, however I doubt this is the issue, since it appears the HTTP request is never even getting called (as referenced by the fact that my HTTP endpoint does not log the request)

Without an error message, and being new to Web3 dev, I am not sure where to start debugging. I found this comment on Github: https://github.com/smartcontractkit/documentation/issues/513 and implemented the suggestion here without luck.

I also found this: Chainlink - Job not being fulfilled but this was not helpful either.

My current considerations for where the error might be:

  1. The oracles are whitelisted and reject my request outright. Have considered creating my own node but want to avoid if possible at this stage.

  2. I have an type error in how I am formatting the request in my contract, like the example in the GitHub exchange I found and referenced above.

EDIT: I am also open to other options beyond Chainlink to connect my contract to an HTTP GET endpoint, if anyone has any suggestions. Thanks!


Solution

  • I've been working on something similar recently and would suggest you try using the kovan network and the oracle that chainlink has there. Even more specifically, I think it would be a good idea to confirm you can get it working using the api, oracle, and jobid listed in the example on that page you are following... here:

    https://docs.chain.link/docs/advanced-tutorial/#contract-example

    Once you get that example working, then you can modify it for your usage. The jobid in that tutorial is for returning a (multiplied) uint256... which, for your API, I think is not what you want as you are wanting bytes32 it sounds like... so when you try to use it with your API that returns bytes32 the jobid would be: 7401f318127148a894c00c292e486ffd as seen here:

    https://docs.chain.link/docs/decentralized-oracles-ethereum-mainnet/

    Another thing that might be your issue, is your api. You say you control what it returns... I think it might have to return a response in bytes format, like Patrick says in his response (and his comments on his response) here:

    Get a string from any API using Chainlink Large Response Example

    Hope this is helpful. If you cannot get the example in the chainlink docs to work, let me know.