Submission and aggregator
This page describes the submission and aggregator services used to submit results from a workflow to a submission contract on an EVM chain.
Submit definition
The submit
field in a service.json file specifies the submission logic for a service. The aggregator
type sends results to an aggregator service, which validates the results and submits them to a target contract on an EVM chain.
"submit": { // Where results are sent"aggregator": { // Type of submission (aggregator)"url": "http://127.0.0.1:8001" // Local aggregator endpoint}},"aggregators": [ // The final submission address that the aggregator will submit to{"evm": { // EVM chain configuration"chain_name": "local", // Local Ethereum chain"address": "0xd6f8ff0036d8b2088107902102f9415330868109", // Submission contract address"max_gas": 5000000 // Maximum gas limit for transactions}}]
Submit can also be set to none
if the service does not need to submit results to a contract. The component will still run, but the results will not be submitted.
Submission contract
A service handler or submission contract handles the logic for verifying the submission of a component's output to the blockchain. The only requirement for a submission contract is that it must implement the handleSignedEnvelope()
function using the IWavsServiceHandler
interface to validate data and signatures using the service manager. This interface is defined in the @wavs
package: https://www.npmjs.com/package/@wavs/solidity?activeTab=code
Workflows can be chained together by setting the trigger event of one workflow to the submission event of another workflow. For more information on chaining workflows, see the Workflows page.
Template submission example
The template submission contract uses the handleSignedEnvelope()
function to validate operator signatures and store the processed data from the component. The DataWithId
struct must match the output format from the component. In the template, each trigger has a unique ID that links the data to its source.
Below is a simplified version of the template submission contract:
import {IWavsServiceManager} from "@wavs/interfaces/IWavsServiceManager.sol";import {IWavsServiceHandler} from "@wavs/interfaces/IWavsServiceHandler.sol";import {ITypes} from "interfaces/ITypes.sol";// Contract must implement IWavsServiceHandler to receive data// ITypes provides the DataWithId struct and other type definitionscontract SimpleSubmit is ITypes, IWavsServiceHandler {/// @notice Service manager instance - used to validate incoming data and signaturesIWavsServiceManager private _serviceManager;/*** @notice Initialize the contract with a service manager* @param serviceManager The service manager instance that will validate data*/constructor(IWavsServiceManager serviceManager) {_serviceManager = serviceManager;}/// @inheritdoc IWavsServiceHandler/// @notice Main entry point for receiving and processing data/// @param envelope Contains the event ID and the actual data payload/// @param signatureData Contains operator signatures for validationfunction handleSignedEnvelope(Envelope calldata envelope, SignatureData calldata signatureData) external {// First validate the data and signatures through the service manager// This ensures the data is properly signed by authorized operators_serviceManager.validate(envelope, signatureData);// Decode the payload into your expected data structure// The payload format must match what your component outputsDataWithId memory dataWithId = abi.decode(envelope.payload, (DataWithId));// At this point, you can safely process the validated data// Add your custom logic here to handle the data}}
Aggregator
The aggregator is used to collect and validate responses from multiple operators before submitting them to the blockchain. It acts as an intermediary that receives signed responses from operators, validates each operator's signature, aggregates signatures when enough operators have responded, and submits the aggregated data to the submission contract. The aggregator supports exact match aggregation, meaning that consensus is reached if a threshold amount of submitted responses from operators are identical. Visit the design considerations page for more information on aggregation and service design.
WAVS currently uses ECDSA signatures for aggregation, but will also support BLS signatures in the future.
Aggregator submission flow
- An operator runs a component which returns a
WasmResponse
containing:payload
: The result dataordering
: Optional ordering information
- The operator creates an Envelope containing the result data and signs it with their private key, creating an signature.
- A Packet containing the envelope, signature, and route information (service ID and workflow ID) is created and sent to the aggregator's
/packet
endpoint. - The aggregator validates the packet's signature by recovering the operator's address and adds it to a queue of packets with the same trigger event and service ID.
- When enough packets accumulate to meet the threshold (determined by the service manager contract), the aggregator:
- Combines the signatures from all packets into a single SignatureData structure
- Validates the combined signatures on-chain through the service manager contract
- If validation succeeds, the aggregator sends the operator signatures and payload result data as a single transaction to the
handleSignedEnvelope()
function on the submit contract specified in the service's manifest. - The
handleSignedEnvelope()
function validates the data and signatures via the service manager contract.