0

Im working on a smart contract in solidity and im having issues with Chainlink function execution. I have this source code for the function:

string private functionCode = "return Functions.encodeString('Hello, World!');";

Then i have this function for making the call:

function requestMatchResult(
        string memory sport,
        string memory eventId,
        uint32 gasLimit
    ) external onlyOwner returns (bytes32) {

        if (bytes(sport).length == 0) revert InvalidInput("Sport cannot be empty");
        if (bytes(eventId).length == 0) revert InvalidInput("Event ID cannot be empty");
        if (gasLimit < 100000) revert InvalidInput("Gas limit too low");
        if (gasLimit > 500000) revert InvalidInput("Gas limit too high");


        FunctionsRequest.Request memory req;
        req.initializeRequestForInlineJavaScript(functionCode);
        

        string[] memory args = new string[](2);
        args[0] = sport;
        args[1] = eventId;
        req.setArgs(args);
        
        bytes32 requestId = _sendRequest(
            req.encodeCBOR(),
            subscriptionId,
            gasLimit,
            donId
        );
        
        lastRequestId = requestId;
        pendingRequests[requestId] = true;
        
        emit RequestSent(requestId, sport, eventId);
        return requestId;
    }

And this is my fufillRequest:

function fulfillRequest(
        bytes32 requestId,
        bytes memory response,
        bytes memory err
    ) internal override {
        if (!pendingRequests[requestId]) {
            revert UnexpectedRequestID(requestId);
        }
        
        pendingRequests[requestId] = false;
        
        if (err.length > 0) {
            string memory errorMsg = string(err);
            requestResults[requestId] = string(abi.encodePacked("Error: ", errorMsg));
            emit RequestFulfilled(requestId, "Error occurred");
            return;
        }
        if (response.length > 0) {
            string memory result = abi.decode(response, (string));
            winner = result;
            requestResults[requestId] = result;
            emit RequestFulfilled(requestId, result);
        } else {
            winner = "No response";
            requestResults[requestId] = "No response";
            emit RequestFulfilled(requestId, "No response");
        }
    }

But i can never successfully make the call. Looking at the chainlink dashboard i see this (the image) (https://ibb.co/Pv8VmmH9) The image shows the chainlink functions console that the Computation was sucessfull and it shows Hello World!, but the callback failed, The on-chain callback failed.

This is how im calling the function from python:

def call_chainlink_function():
    """Call Chainlink function to get winner"""
    txn = contract.functions.requestMatchResult(
        "some_string", 
        "some_string", 
        100000
    ).build_transaction({
        "from": account.address,
        "nonce": web3.eth.get_transaction_count(account.address),
        "gas": 300000,
        "gasPrice": web3.eth.gas_price,
    })
    
    signed_txn = account.sign_transaction(txn)
    tx_hash = web3.eth.send_raw_transaction(signed_txn.raw_transaction)
    tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
    
    if tx_receipt.status == 1:
        last_request_id = contract.functions.lastRequestId().call()
        request_id_hex = "0x" + last_request_id.hex()
        
        for _ in range(30):
            is_pending = contract.functions.isRequestPending(request_id_hex).call()
            if not is_pending:
                return True
            time.sleep(10)
        
        print("Request timeout after 5 minutes")
        return False
    
    return False

Calling other functions is okay (for example getting value of a string, setting value etc.)

I've already tried changing the gas value.

2
  • I don't see image in question. If image shows text then better put it as text, not image. Commented Sep 24 at 16:18
  • Thank you @furas I edited the post to include a link to the image and an explanation. Here is the link here also: ibb.co/Pv8VmmH9 Commented Sep 24 at 17:22

1 Answer 1

0

The Functions.encodeString('Hello, World!') call returns the result of abi.encodePacked(), which cannot be properly decoded using abi.decode(response, (string)). This mismatch between the encoded bytes and the expected ABI encoding rules causes the transaction to revert, leading to a "gas insufficient" error in the Chainlink Functions dashboard. Note that this is a common Solidity execution error, often not due to an actual gas limit shortfall, but rather because the transaction inherently fails.

To enable proper decoding, you have two options:

  1. Encode using Ethers.js in the source JavaScript script: Modify the line submitting to the Chainlink Functions node from

    string private functionCode = "return Functions.encodeString('Hello, World!');";
    

    to

    string private SOURCE = 'const ethers = await import("npm:[email protected]"); const encoded = ethers.AbiCoder.defaultAbiCoder().encode(["string"], ["Hello World!"]); return ethers.getBytes(encoded);';
    

    This approach ensures the returned bytes from Functions are ABI-encoded, allowing them to be decoded successfully via abi.decode(response, (string)).

  2. Directly convert the packed-encoded bytes to a string in the fulfillment function: Replace the line

    string memory result = abi.decode(response, (string));
    

    with

    string memory result = string(response);
    

    This bypasses ABI decoding by treating the packed bytes as a raw string.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.