To my understanding, the standard form of returning values to the front-end/web3 is subscribing to the appropriate event(s) emitted to the blockchain (data stored on the blockchain linked through events), though I wonder how one can return/retrieve the data in memory within a callback function without emitting said data onto the blockchain/storage for everyone to see?

function callbackFunction(bytes memory data) public returns (bytes memory) {
    // manipulate data then return
    return data;

Something along the lines of "subscribing" to the execution of a callback function gives an idea of what I'm looking for because data can be stored temporarily in memory.

I greatly appreciate any feedback or insight!

  • I'm not sure I understand your question. Can you add more details? If there's code involved in your analysis, can you share the code? Screenshots or anything that could allow us to understand your concern more. Sep 21, 2022 at 22:01
  • @JeremyThen Hey there - thanks for taking the time to review my question. I updated it as requested. Please advise if I need to elaborate on something. Sep 21, 2022 at 22:31

1 Answer 1


As long as your function is declared as view or pure you can expect the values directly by calling the function like (from web3js):

const contract = new web3.eth.Contract(
    from: fromAddress,

const data = await contract.methods.callbackFunction().call();

Notice I'm calling the callbackFunction() with .call(). This means that we are calling a pure or view function, or that we only would like to know what would be the result of a call to a function while not broadcasting the transaction through the network. When we call a pure or view function, our transaction will not be broadcasted and will not be included in a block, thus, we get the response right away. Otherwise, we don't know when our transaction will be mined and hence we cannot wait for a response. In this case, we need to emit events and subscribe to them to get the data that we need.

If you are going to write utility functions in a smart contract that will not modify the state of the smart contract, then you can declare those functions as pure or view and call them and expect a value right away.

Take a look at this example where I declare your functions, one version as pure and another version as view:

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

contract Contract {

    function callbackFunction(bytes memory data) public pure returns (bytes memory) {
    // manipulate data then return
        return data;

    function callbackFunction2(bytes memory data) public view returns (bytes memory) {
    // manipulate data then return
        return data;

    function doSomething(bytes memory data) public returns (bytes memory) {
        // manipulate data, update the state then return
        return data;


Since those functions don't modify the state of the smart contract, I can call those functions and expect a value immediately.

For example, notice how doSomething() modifies the state. If we call that function from web3js:

const transactionReceipt = await contract.methods.doSomething().send();

Notice how I'm using .send(). This means that I'm calling a non-view/non-pure function that will modify the state, hence, I need to broadcast my transaction and pay gas, so it is included in a block. Because of this, that function call will not return the data, but a transactionReceipt. It cannot return the data because the function probably has not been included in a block and mined yet. All this is uncertain, your transaction can stay in the mempool for a long time, or be mined immediately, who knows. But you get a transaction receipt telling you that your transaction has been successfully broadcasted and is waiting to be included in a block.

If we call the same function doSomething() from web3js with .call():

const data = await contract.methods.doSomething().call();

Then we would get the data right away. But no changes to the contract state will be done because you didn't broadcast your transaction to the network to be included in a block, you just told a node to execute your function and return what would happen if you actually broadcasted your transaction, but without spending gas. This is useful and is commonly used by wallets like Metamask and other wallets, that make a local .call() to a node to check what would happen if the transaction was actually broadcasted. This allows us to know if a transaction would fail for any reason, thus, saving us gas by preventing us from broadcasting a transaction that would fail.


If your contract function does not modify the state, declare it as pure or view. You can call these functions any time and expect the value right away without subscribing to an event.

If the contract function modifies the state (from web3js it was invoked using .send(), you will need to emit and subscribe to an event that contains the data that you need. You can invoke it from web3js with .call() to get the result right away, but any changes to the state of the contract will not be persisted because a .call() is not broadcasted through the network and thus not included in a block.

  • Thank you much for going into detail regarding the functionality you have highlighted, which gives front-end clients a way to view data on the blockchain. Do you know if returning the data in memory within a callback function to the front end is possible without calling it explicitly? I thought about keeping an initial function "alive" until the callback function executes separately, but there doesn't appear to be a way to move over data. Let's say the data was private (that's why it's in memory), and we didn't want to emit an event with the data (which would store on the blockchain). Sep 22, 2022 at 16:05

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.