BLOG — Updates

136 days ago

Enhance Developer Experience with Gelato Functions Callbacks

Turbocharge your DevX by 1000x with Gelato Functions Callbacks!

With the NEW Gelato Functions update - Callbacks, enhance your developer experience with more feedback on the transaction lifecycle.

Gelato's Functions are serverless and event-driven tools that are specifically designed for automating blockchain transactions using both off-chain and on-chain data.

What are Callbacks?

The introduction of Callbacks within Gelato Functions now allows developers to efficiently manage transaction outcomes. This feature offers a robust framework to handle various scenarios in automated tasks, ultimately enhancing the functionality of decentralized applications (dApps).

Why are Callbacks Essential?

  • Enhanced Control: Callbacks give you the ability to respond and adapt to the success or failure of your transactions, offering greater control over your dApp's automated processes.
  • Error Handling: Implement comprehensive error handling to ensure dApp robustness and reliability.
  • Custom Logic Implementation: Execute custom logic based on transaction outcomes, like sending alerts, database updates, or triggering additional transactions.

Types of Callbacks

Checkout how callbacks are implemented in real-world scenarios in our GitHub repository

onSuccess Callback

These are triggered after a successful on-chain execution. This callback is ideal for tracking transactions and post-processing.

Web3Function.onSuccess(async (context: Web3FunctionSuccessContext) => {
  const { transactionHash } = context;
  console.log("onSuccess: txHash: ", transactionHash);
  // Additional onSuccess logic...
});

onFail Callback

This callback is invoked when an execution encounters issues such as insufficient funds, failed simulations, or execution revert. It's crucial for error handling and implementing fallback strategies.

Web3Function.onFail(async (context: Web3FunctionFailContext) => {
  const { reason, transactionHash, callData } = context;
  // Handle various failure scenarios...
});

Example Use Case: Oracle Price Update

Consider a scenario where you have an Oracle smart contract that needs regular updates on cryptocurrency prices from an external API. Here’s how you can utilize callbacks:

onRun Function:

  • Prepares call data for updating the Oracle with the latest cryptocurrency price.

onSuccess Callback:

  • Logs the transaction hash.
  • Updates the database with the new price.
  • Tries to fetch the current price and updates it in storage; logs errors if any occur.

onFail Callback:

  • Handles errors during the update process (API failures, blockchain reverts).
  • Constructs detailed alert messages based on the failure reason.
  • Sends alerts, like Slack notifications, for significant failures.

onSuccess Function Example:

//Web3 Function onSuccess callback
Web3Function.onSuccess(async (context: Web3FunctionSuccessContext) => {
  const { userArgs, transactionHash, storage } = context;
  console.log("userArgs: ", userArgs.canExec);
  console.log("onSuccess: txHash: ", transactionHash);

  const currency = (userArgs.currency as string) ?? "ethereum";
  let price = 0;

  try {
    const price = await getCurrentPrice(currency);
    console.log(`Current Price: ${price}`);
    await storage.set("lastPrice", price.toString());
  } catch (err) {
    console.error("Failed to update price:", err);
  }

  // Update storage with the current price
  await storage.set("lastPrice", price.toString());
});

In this onSuccess callback, we have a few key elements:

  • Context Variables: We access important information from the execution context, such as userArgs, transactionHash, and storage. These provide data about the current execution and allow us to make decisions based on it.
  • Logging: We log relevant information like transactionHash to keep track of the successful transaction. This is valuable for tracking and auditing purposes.
  • Currency Price Update: Inside a try-catch block, we attempt to fetch the current price of a cryptocurrency (getCurrentPrice(currency)). If successful, we log the price and update it in the storage. This demonstrates how you can perform additional actions based on the success of the primary execution.
  • Error Handling: In case there's an error while fetching the price, we catch the error and log it. This showcases error handling within the onSuccess callback.
  • Storage Update: Finally, we update the lastPrice in the storage, ensuring that the new price is stored for future reference.

onFail Function Example:

//Web3 Function onFail callback
Web3Function.onFail(async (context: Web3FunctionFailContext) => {
  const { userArgs, reason } = context;

  let alertMessage = `Web3 Function Failed. Reason: ${reason}`;
  console.log("userArgs: ", userArgs.canExec);

  if (reason === "ExecutionReverted") {
    alertMessage += ` TxHash: ${context.transactionHash}`;
    console.log(`onFail: ${reason} txHash: ${context.transactionHash}`);
  } else if (reason === "SimulationFailed") {
    alertMessage += ` callData: ${JSON.stringify(context.callData)}`;
    console.log(
      `onFail: ${reason} callData: ${JSON.stringify(context.callData)}`
    );
  } else {
    console.log(`onFail: ${reason}`);
  }

  // Send Slack alert if specified
  await sendSlackAlert(alertMessage);
});

Now let’s explore the onFail callback:

  • Context Variables: Similar to the onSuccess callback, we access context variables like userArgs and reason to understand why the execution failed.
  • Alert Message: We construct an alertMessage that provides details about the failure, including the reason. This message can be crucial for debugging and understanding what went wrong.
  • Conditional Handling: Depending on the reason for failure, we customize the alertMessage. For example, if the reason is "ExecutionReverted," we include the transactionHash to pinpoint the failed transaction. This conditional handling is essential for providing clear information on different failure scenarios.
  • Slack Alert: If needed, we send a Slack alert using sendSlackAlert(alertMessage). This demonstrates how you can integrate external systems to notify stakeholders about failures.

These examples showcase how onSuccess and onFail callbacks allow you to respond differently to the success or failure of your transactions, implement error handling, and take specific actions based on the outcome. They provide a powerful mechanism for customizing the behavior of your decentralized application to meet your exact requirements.

For those eager to dive into the world of Gelato Functions and experience the power of callbacks firsthand - please head over to our Github repo and access the code example mentioned here.

Testing your Callbacks

To ensure the reliability of your callbacks, Gelato Functions provide a local testing environment. This allows you to simulate both successful and failed executions, helping you fine-tune your callback logic before deploying it live. You can make use of the –onFail or –onSuccess flags for this purpose.

# Test onFail Callback
yarn test src/web3-functions/callbacks/index.ts --logs --onFail

# Test onSuccess Callback
yarn test src/web3-functions/callbacks/index.ts --logs --onSuccess

Conclusion

In conclusion, Gelato Functions' callbacks offer a dynamic and powerful way to take control of your decentralized applications (dApps). With the ability to respond to both success and failure, callbacks grant you unmatched flexibility. You can fine-tune your dApp's behavior, handle errors with ease, and even introduce custom logic to cater to your specific needs.

About Gelato

Gelato is a Web3 Cloud Platform empowering developers to create automated, gasless, and off-chain-aware Layer 2 chains and smart contracts. Over 400 web3 projects rely on Gelato for years to facilitate millions of transactions in DeFi, NFTs, and gaming.

  • Gelato RaaS: Deploy your own tailor-made ZK or OP L2 chains in a single click with native Account Abstraction and all Gelato middleware baked in.

  • VRF: Gelato VRF provides fast, on-chain verifiable randomness for blockchain applications.

  • Functions: Serverless, event-driven functions to automate blockchain transactions.

  • Relay: Give your users access to reliable, robust, and scalable gasless transactions via a simple-to-use API.

  • Account Abstraction SDK: Gelato has partnered with Safe, to build a fully-fledged Account Abstraction SDK, combining Gelato's industry's best gasless transaction capabilities, with the industry's most secure smart contract wallet.

Subscribe to our newsletter and turn on your Twitter notifications to get the most recent updates about the Gelato ecosystem! If you are interested in being part of the Gelato team and building the future of the Internet browse the open positions and apply here.