Blockchain

使用 ChainlinkClient.sol v0.8.0 時找不到錯誤成員add

  • February 22, 2022

我正在嘗試使用 ChainlinkAPIConsumer範例,並且我正在導入v0.8/ChainlinkClient.sol文件。在編譯APIConsumer契約時,我遇到了錯誤。

錯誤

TypeError: Member "add" not found or not visible after argument-dependent lookup in struct Chainlink.Request memory.
 --> contracts/APIConsumer.sol:44:9:
  |
44 |         request.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");
  |         ^^^^^^^^^^^

使用時沒有顯示任何錯誤v0.6/ChainlinkClient.sol

契約

APIConsumer.sol

//SPDX-License-Identifier: Unlicense

pragma solidity ^0.8.0;

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

/**
* @notice reference link for Polygon-Chainlink API's integration
* https://docs.matic.network/docs/develop/oracles/chainlink/
*/
contract APIConsumer is ChainlinkClient {
 
   uint256 public volume;
   
   address private oracle;
   bytes32 private jobId;
   uint256 private fee;
   
   /**
    * Network: Matic Mumbai Testnet
    * Oracle: 0x58bbdbfb6fca3129b91f0dbe372098123b38b5e9
    * Job ID: da20aae0e4c843f6949e5cb3f7cfe8c4
    * LINK address: 0x326C977E6efc84E512bB9C30f76E30c160eD06FB
    * Fee: 0.01 LINK
    */
   constructor() {
       //setPublicChainlinkToken;
       setChainlinkToken(0x326C977E6efc84E512bB9C30f76E30c160eD06FB);
       //oracle = 0x58bbdbfb6fca3129b91f0dbe372098123b38b5e9;
       oracle = 0x58BBDbfb6fca3129b91f0DBE372098123B38B5e9;
       jobId = "da20aae0e4c843f6949e5cb3f7cfe8c4";
       fee = 0.01 * 10 ** 18; // 0.01 LINK
   }
   
   /**
    * Create a Chainlink request to retrieve API response, find the target
    * data, then multiply by 1000000000000000000 (to remove decimal places from data).
    */
   function requestVolumeData() public returns (bytes32 requestId) 
   {
       Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
       
       // Set the URL to perform the GET request on
       request.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");
       
       // Set the path to find the desired data in the API response, where the response format is:
       request.add("path", "RAW.ETH.USD.VOLUME24HOUR");
       
       // Multiply the result by 1000000000000000000 to remove decimals
       int timesAmount = 10**18;
       request.addInt("times", timesAmount);
       
       // Sends the request
       return sendChainlinkRequestTo(oracle, request, fee);
   }
   
   /**
    * Receive the response in the form of uint256
    */ 
   function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId)
   {
       volume = _volume;
   }
}

v0.8/ChainlinkClient.sol

從 複製它node_modules

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

import "./Chainlink.sol";
import "./interfaces/ENSInterface.sol";
import "./interfaces/LinkTokenInterface.sol";
import "./interfaces/OperatorInterface.sol";
import "./interfaces/PointerInterface.sol";
import { ENSResolver as ENSResolver_Chainlink } from "./vendor/ENSResolver.sol";

/**
* @title The ChainlinkClient contract
* @notice Contract writers can inherit this contract in order to create requests for the
* Chainlink network
*/
contract ChainlinkClient {
 using Chainlink for Chainlink.Request;

 uint256 constant internal LINK_DIVISIBILITY = 10**18;
 uint256 constant private AMOUNT_OVERRIDE = 0;
 address constant private SENDER_OVERRIDE = address(0);
 uint256 constant private ORACLE_ARGS_VERSION = 1;
 uint256 constant private OPERATOR_ARGS_VERSION = 2;
 bytes32 constant private ENS_TOKEN_SUBNAME = keccak256("link");
 bytes32 constant private ENS_ORACLE_SUBNAME = keccak256("oracle");
 address constant private LINK_TOKEN_POINTER = 0xC89bD4E1632D3A43CB03AAAd5262cbe4038Bc571;

 ENSInterface private ens;
 bytes32 private ensNode;
 LinkTokenInterface private link;
 OperatorInterface private oracle;
 uint256 private requestCount = 1;
 mapping(bytes32 => address) private pendingRequests;

 event ChainlinkRequested(
   bytes32 indexed id
 );
 event ChainlinkFulfilled(
   bytes32 indexed id
 );
 event ChainlinkCancelled(
   bytes32 indexed id
 );

 /**
  * @notice Creates a request that can hold additional parameters
  * @param specId The Job Specification ID that the request will be created for
  * @param callbackAddress The callback address that the response will be sent to
  * @param callbackFunctionSignature The callback function signature to use for the callback address
  * @return A Chainlink Request struct in memory
  */
 function buildChainlinkRequest(
   bytes32 specId,
   address callbackAddress,
   bytes4 callbackFunctionSignature
 )
   internal
   pure
   returns (
     Chainlink.Request memory
   )
 {
   Chainlink.Request memory req;
   return req.initialize(specId, callbackAddress, callbackFunctionSignature);
 }

 /**
  * @notice Creates a Chainlink request to the stored oracle address
  * @dev Calls `chainlinkRequestTo` with the stored oracle address
  * @param req The initialized Chainlink Request
  * @param payment The amount of LINK to send for the request
  * @return requestId The request ID
  */
 function sendChainlinkRequest(
   Chainlink.Request memory req,
   uint256 payment
 )
   internal
   returns (
     bytes32
   )
 {
   return sendChainlinkRequestTo(address(oracle), req, payment);
 }

 /**
  * @notice Creates a Chainlink request to the specified oracle address
  * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to
  * send LINK which creates a request on the target oracle contract.
  * Emits ChainlinkRequested event.
  * @param oracleAddress The address of the oracle for the request
  * @param req The initialized Chainlink Request
  * @param payment The amount of LINK to send for the request
  * @return requestId The request ID
  */
 function sendChainlinkRequestTo(
   address oracleAddress,
   Chainlink.Request memory req,
   uint256 payment
 )
   internal
   returns (
     bytes32 requestId
   )
 {
   return rawRequest(oracleAddress, req, payment, ORACLE_ARGS_VERSION, oracle.oracleRequest.selector);
 }

 /**
  * @notice Creates a Chainlink request to the stored oracle address
  * @dev This function supports multi-word response
  * @dev Calls `requestOracleDataFrom` with the stored oracle address
  * @param req The initialized Chainlink Request
  * @param payment The amount of LINK to send for the request
  * @return requestId The request ID
  */
 function requestOracleData(
   Chainlink.Request memory req,
   uint256 payment
 )
   internal
   returns (
     bytes32
   )
 {
   return requestOracleDataFrom(address(oracle), req, payment);
 }

 /**
  * @notice Creates a Chainlink request to the specified oracle address
  * @dev This function supports multi-word response
  * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to
  * send LINK which creates a request on the target oracle contract.
  * Emits ChainlinkRequested event.
  * @param oracleAddress The address of the oracle for the request
  * @param req The initialized Chainlink Request
  * @param payment The amount of LINK to send for the request
  * @return requestId The request ID
  */
 function requestOracleDataFrom(
   address oracleAddress,
   Chainlink.Request memory req,
   uint256 payment
 )
   internal
   returns (
     bytes32 requestId
   )
 {
   return rawRequest(oracleAddress, req, payment, OPERATOR_ARGS_VERSION, oracle.requestOracleData.selector);
 }

 /**
  * @notice Make a request to an oracle
  * @param oracleAddress The address of the oracle for the request
  * @param req The initialized Chainlink Request
  * @param payment The amount of LINK to send for the request
  * @param argsVersion The version of data support (single word, multi word)
  * @return requestId The request ID
  */
 function rawRequest(
   address oracleAddress,
   Chainlink.Request memory req,
   uint256 payment,
   uint256 argsVersion,
   bytes4 funcSelector
 )
   private
   returns (
     bytes32 requestId
   )
 {
   requestId = keccak256(abi.encodePacked(this, requestCount));
   req.nonce = requestCount;
   pendingRequests[requestId] = oracleAddress;
   emit ChainlinkRequested(requestId);
   bytes memory encodedData = abi.encodeWithSelector(
     funcSelector,
     SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address
     AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent
     req.id,
     req.callbackAddress,
     req.callbackFunctionId,
     req.nonce,
     argsVersion,
     req.buf.buf);
   require(link.transferAndCall(oracleAddress, payment, encodedData), "unable to transferAndCall to oracle");
   requestCount += 1;
 }

 /**
  * @notice Allows a request to be cancelled if it has not been fulfilled
  * @dev Requires keeping track of the expiration value emitted from the oracle contract.
  * Deletes the request from the `pendingRequests` mapping.
  * Emits ChainlinkCancelled event.
  * @param requestId The request ID
  * @param payment The amount of LINK sent for the request
  * @param callbackFunc The callback function specified for the request
  * @param expiration The time of the expiration for the request
  */
 function cancelChainlinkRequest(
   bytes32 requestId,
   uint256 payment,
   bytes4 callbackFunc,
   uint256 expiration
 )
   internal
 {
   OperatorInterface requested = OperatorInterface(pendingRequests[requestId]);
   delete pendingRequests[requestId];
   emit ChainlinkCancelled(requestId);
   requested.cancelOracleRequest(requestId, payment, callbackFunc, expiration);
 }

 /**
  * @notice Sets the stored oracle address
  * @param oracleAddress The address of the oracle contract
  */
 function setChainlinkOracle(
   address oracleAddress
 )
   internal
 {
   oracle = OperatorInterface(oracleAddress);
 }

 /**
  * @notice Sets the LINK token address
  * @param linkAddress The address of the LINK token contract
  */
 function setChainlinkToken(
   address linkAddress
 )
   internal
 {
   link = LinkTokenInterface(linkAddress);
 }

 /**
  * @notice Sets the Chainlink token address for the public
  * network as given by the Pointer contract
  */
 function setPublicChainlinkToken() 
   internal
 {
   setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress());
 }

 /**
  * @notice Retrieves the stored address of the LINK token
  * @return The address of the LINK token
  */
 function chainlinkTokenAddress()
   internal
   view
   returns (
     address
   )
 {
   return address(link);
 }

 /**
  * @notice Retrieves the stored address of the oracle contract
  * @return The address of the oracle contract
  */
 function chainlinkOracleAddress()
   internal
   view
   returns (
     address
   )
 {
   return address(oracle);
 }

 /**
  * @notice Allows for a request which was created on another contract to be fulfilled
  * on this contract
  * @param oracleAddress The address of the oracle contract that will fulfill the request
  * @param requestId The request ID used for the response
  */
 function addChainlinkExternalRequest(
   address oracleAddress,
   bytes32 requestId
 )
   internal
   notPendingRequest(requestId)
 {
   pendingRequests[requestId] = oracleAddress;
 }

 /**
  * @notice Sets the stored oracle and LINK token contracts with the addresses resolved by ENS
  * @dev Accounts for subnodes having different resolvers
  * @param ensAddress The address of the ENS contract
  * @param node The ENS node hash
  */
 function useChainlinkWithENS(
   address ensAddress,
   bytes32 node
 )
   internal
 {
   ens = ENSInterface(ensAddress);
   ensNode = node;
   bytes32 linkSubnode = keccak256(abi.encodePacked(ensNode, ENS_TOKEN_SUBNAME));
   ENSResolver_Chainlink resolver = ENSResolver_Chainlink(ens.resolver(linkSubnode));
   setChainlinkToken(resolver.addr(linkSubnode));
   updateChainlinkOracleWithENS();
 }

 /**
  * @notice Sets the stored oracle contract with the address resolved by ENS
  * @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously
  */
 function updateChainlinkOracleWithENS()
   internal
 {
   bytes32 oracleSubnode = keccak256(abi.encodePacked(ensNode, ENS_ORACLE_SUBNAME));
   ENSResolver_Chainlink resolver = ENSResolver_Chainlink(ens.resolver(oracleSubnode));
   setChainlinkOracle(resolver.addr(oracleSubnode));
 }

 /**
  * @notice Ensures that the fulfillment is valid for this contract
  * @dev Use if the contract developer prefers methods instead of modifiers for validation
  * @param requestId The request ID for fulfillment
  */
 function validateChainlinkCallback(
   bytes32 requestId
 )
   internal
   recordChainlinkFulfillment(requestId)
   // solhint-disable-next-line no-empty-blocks
 {}

 /**
  * @dev Reverts if the sender is not the oracle of the request.
  * Emits ChainlinkFulfilled event.
  * @param requestId The request ID for fulfillment
  */
 modifier recordChainlinkFulfillment(
   bytes32 requestId
 )
 {
   require(msg.sender == pendingRequests[requestId],
           "Source must be the oracle of the request");
   delete pendingRequests[requestId];
   emit ChainlinkFulfilled(requestId);
   _;
 }

 /**
  * @dev Reverts if the request is already pending
  * @param requestId The request ID for fulfillment
  */
 modifier notPendingRequest(
   bytes32 requestId
 )
 {
   require(pendingRequests[requestId] == address(0), "Request is already pending");
   _;
 }
}

您需要using Chainlink for Chainlink.Request;在契約聲明之後添加該行,如下所示:

contract APIConsumer is ChainlinkClient {
   using Chainlink for Chainlink.Request;
 
   uint256 public volume;
   
   address private oracle;
   bytes32 private jobId;
   uint256 private fee;

引用自:https://ethereum.stackexchange.com/questions/107105