I am currently exploring the Chainlink API Consumer smart contract that brings off-chain data to the smart contract through GET request.

There is an understandable example of how to perform such task. I am curious, how to initialize the third argument in buildChainlinkRequest function during the contract construction so that instead of this.fulfill.selector will be placed another argument?

From this:

Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);

To customizable third argument:

Chainlink.Request memory request = buildChainlinkRequest(jobId, callback, callbackFunctionSignature);

For illustration something like this idea:

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

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

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

    // For example: 0xContractAddr.contractFunction.selector;
    bytes4 callbackFunctionSignature; // <-- added
    address callback; // <-- added
    constructor(bytes4 _callbackFunctionSignature) {  // <-- added
        oracle = 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8;
        jobId = "d5270d1c311941d0b08bead21fea7747";
        fee = 0.1 * 10 ** 18; // (Varies by network and job)

        callbackFunctionSignature = _callbackFunctionSignature; // <-- added
    function changeCallbackFunctionSignature(bytes4 _callbackFunctionSignature) public {
        callbackFunctionSignature = _callbackFunctionSignature;
    } // <-- added

    function changeCallback(address _callback) public {
        callback = _callback;
    } // <-- added

    function requestVolumeData() public returns (bytes32 requestId) 
        Chainlink.Request memory request = buildChainlinkRequest(jobId, callback, callbackFunctionSignature); // <-- added

        request.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");
        request.add("path", "RAW,ETH,USD,VOLUME24HOUR"); // Chainlink nodes 1.0.0 and later support this format

        int timesAmount = 10**18;
        request.addInt("times", timesAmount);
        // Sends the request
        return sendChainlinkRequestTo(oracle, request, fee);
    function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId)
        volume = _volume;


I've tried to use abi.encodeWithSelector() but it modifies only function + arguments without specifying a contract address unless you call.

TL;DR. How to make the callbackFunctionSignature parameter in buildChainlinkRequest function dinamic?

1 Answer 1


For now, this is not currently supported in the docs, so it is not recommended to go with this approach as it breaks the recording of requestId's and you must remove the modifier which prevents addresses other than the Oracle to call the fulfill() function. If you really want to test this technique, you can, however, you'll need to manually modify some code (at your own security risk):

The default behavior in the ChainlinkClient.sol (line 104) import is to automatically put the receiving contract as the same contract that sent the request. You must change line 104 of the import to state this instead: req.callbackAddress. You also have to remove the recordChainlinkFulfillment(_requestId) modifier on the fulfill() method. You're going to want at least to put your own require statement here to be sure the only entity that can run the fulfill() method is the oracle you sent the request to.

Doing this will work, but again as this is currently not supported in the docs, you must take extra precautions in ensuring this is done securely.

Your Answer

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

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