Receiving Callbacks

What are Callback Handlers?

The hooks system is very flexible and allows guardians to invoke arbitrary operations, however, some interactions may trigger callbacks into the Aera Vault. A common instance is flash loans which need to be paid back atomically and therefore only provide access to funds through a callback.

Callback handlers provide a way for guardians to prepare for a callback by “queueing up” additional operations that would be executed during the callback. These operations are protected by the same Merkle tree (see Merkle Trees) and hooks (see Using Configurable Hooks) as general Aera vault operations (see Operations and submit()).

Why They Matter

Aera Vaults can inherit from BaseVault and add functions to respond to callbacks. However, this approach defeats the purpose of the Aera system which is to allow guardians to take flexible operations that are informed by off chain computation with onchain protections.

Callback handlers provide significantly more flexibility and together with input/output chaining allow guardians to implement complex multi-step operations that were previously only available to MEV bots.

How to use Callback Handlers

To invoke a callback handler, you need to do the following:

  • Decide which operation will trigger a callback into the Aera vault

  • Call submit and for that operation:

    • Set hasCallback to 1,

    • Provide selector, the function selector for the callback function that the vault will be called with,

    • Provide calldataOffset the specific byte in the calldata that Aera Vault should extract the operations for,

    • Provide caller , the contract that will call the Aera Vault.

Whenever the callback occurs, the Aera Vault will check if the callback is expected with the given selector and caller. If so, it will decode the series of operations starting at the calldata offset and execute them while complying to the guardian's Merkle tree.

Consider Morpho flash loans as an example. The following would happen:

  • The guardian creates a submit transaction with the operation morpho.flashLoan ;

  • flashLoan accepts 3 arguments: token, amount and data. The guardian encodes all the operations which should trigger on the callback in the data argument;

  • The guardian also adds a callback to the operation using the selector of onMorphoFlashLoan(amount, data) (0x31f57072) using morpho as the caller (0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb) and specifying the calldata index of data variable in onMorphoFlashLoan (100). Note that 100 is chosen because we need to skip the pointer and the length variable as CalldataReader uses a more compact length encoding;

  • Now submit executes and calls the morpho contract;

  • Morpho executes the onMorphoFlashLoan callback which is handled by Aera. Morpho forwards all data provided to flashLoan in the data argument. In the handler, the vault decodes operations and runs them from the handler.

Caveats

Callback handlers only exist during a given submit call by a guardian. It means that they cannot be used for asynchronous interactions (such as receiving a settlement order in response to an RFQ) and that the same callback function can trigger different operations in different submit calls. To add new functions to an Aera vault, an extension to BaseVault is recommended.

Only “pull”-based flash loans are currently supported because push-based flash loans require a transfer operation to dynamically allow repayment based on how much was borrowed. Push-based flash loans can still be supported by creating a dedicated handler contract.

Last updated