diff --git a/README.md b/README.md index ae6b4f8a..d5a8895d 100644 --- a/README.md +++ b/README.md @@ -32,121 +32,9 @@ ap-avs aggregator Note: The Ava Protocol team currently manages the aggregator, and the communication IP address between the operator and the aggregator is hardcoded in the operator. -### Configurable Fee Rates - -The aggregator supports configurable fee rates for workflow execution and monitoring. This allows for dynamic pricing adjustments without code deployments, environment-specific pricing, and A/B testing of pricing models. - -#### Configuration Overview - -Fee rates are completely **optional** and **backward compatible**. The aggregator will work exactly as before without any configuration changes. When fee rates are configured, they override the hardcoded defaults. - -#### Adding Fee Configuration - -To configure custom fee rates, add a `fee_rates:` section to your existing aggregator YAML configuration file: - -```yaml -# Your existing aggregator config (unchanged) -environment: development -db_path: /tmp/ap-avs/db -ecdsa_private_key: your_private_key_here -# ... other existing config fields ... - -# 🆕 Optional fee rates configuration -fee_rates: - # Base fees (one-time per workflow) - base_fee_usd: 0.0 - - # Monitoring fees (per minute) - cost to monitor triggers - manual_monitoring_fee_usd_per_minute: 0.0 # Manual triggers free - fixed_time_monitoring_fee_usd_per_minute: 0.000017 # ~$0.01/day - cron_monitoring_fee_usd_per_minute: 0.000033 # ~$0.02/day - block_monitoring_fee_usd_per_minute: 0.000033 # ~$0.02/day - event_monitoring_fee_usd_per_minute: 0.000083 # ~$0.05/day base - - # Per-execution fees - cost for each trigger activation - manual_execution_fee_usd: 0.0 # Manual executions free - scheduled_execution_fee_usd: 0.005 # $0.005 per scheduled execution - block_execution_fee_usd: 0.01 # $0.01 per block trigger - event_execution_fee_usd: 0.01 # $0.01 per event trigger - - # Event monitoring scaling factors - event_address_fee_usd_per_minute: 0.000008 # ~$0.005/day per address - event_topic_fee_usd_per_minute: 0.000003 # ~$0.002/day per topic -``` - -#### Configuration Files - -The aggregator uses configuration files from the `config/` directory: - -- **Default**: `./config/aggregator.yaml` -- **Custom**: Specify with `--config` flag - -**Available config files:** -- `config/aggregator.yaml` - Default configuration -- `config/aggregator-sepolia.yaml` - Sepolia testnet -- `config/aggregator-base.yaml` - Base network -- `config/aggregator-ethereum.yaml` - Ethereum mainnet - -#### Starting with Custom Config - -```bash -# Use default config (./config/aggregator.yaml) -./ap-avs aggregator - -# Use specific config file -./ap-avs aggregator --config ./config/aggregator-sepolia.yaml -./ap-avs aggregator -c ./path/to/your/config.yaml -``` - -#### Pricing Strategies - -**All fields are optional** - only specify rates you want to override: - -**Beta Testing (Free Everything):** -```yaml -fee_rates: - scheduled_execution_fee_usd: 0.0 - block_execution_fee_usd: 0.0 - event_execution_fee_usd: 0.0 - # All monitoring fees default to existing values -``` - -**Premium Pricing (Selective Overrides):** -```yaml -fee_rates: - # Only override specific rates - block_execution_fee_usd: 0.02 # 2x default rate - event_execution_fee_usd: 0.015 # 1.5x default rate - # All other fees use hardcoded defaults -``` - -**Environment-Specific Pricing:** -```yaml -# Production - Higher rates -fee_rates: - scheduled_execution_fee_usd: 0.01 # 2x default - -# Development - Free rates -fee_rates: - scheduled_execution_fee_usd: 0.0 # Free for development -``` +### Fee Estimation -#### Default Values - -When no `fee_rates` section is provided, these hardcoded defaults are used: - -- **Base Fee**: $0.00 (one-time per workflow) -- **Manual Monitoring**: $0.00/minute (free) -- **Fixed Time Monitoring**: $0.000017/minute (~$0.01/day) -- **Cron Monitoring**: $0.000033/minute (~$0.02/day) -- **Block Monitoring**: $0.000033/minute (~$0.02/day) -- **Event Monitoring**: $0.000083/minute (~$0.05/day base) -- **Manual Execution**: $0.00 (free) -- **Scheduled Execution**: $0.005 per execution -- **Block Execution**: $0.01 per execution -- **Event Execution**: $0.01 per execution -- **Event Address Fee**: $0.000008/minute per monitored address -- **Event Topic Fee**: $0.000003/minute per topic filter +See [docs/FEE_ESTIMATION.md](docs/FEE_ESTIMATION.md) for the fee pricing model, configuration, and implementation details. #### Benefits diff --git a/aggregator/rpc_server.go b/aggregator/rpc_server.go index 56a8868f..948947df 100644 --- a/aggregator/rpc_server.go +++ b/aggregator/rpc_server.go @@ -1255,8 +1255,7 @@ func (r *RpcServer) EstimateFees(ctx context.Context, req *avsproto.EstimateFees r.config.Logger.Info("✅ fee estimation completed successfully", "user", user.Address.String(), - "final_total_usd", resp.FinalTotal.UsdAmount, - "estimation_method", resp.GasFees.EstimationMethod) + "pricing_model", resp.PricingModel) return resp, nil } diff --git a/config/aggregator.example.yaml b/config/aggregator.example.yaml index c3a6b037..d9934656 100644 --- a/config/aggregator.example.yaml +++ b/config/aggregator.example.yaml @@ -76,28 +76,17 @@ approved_operators: - "0xc6b87cc9e85b07365b6abefff061f237f7cf7dc3" # Operator 2 - "0xa026265a0f01a6e1a19b04655519429df0a57c4e" # Operator 3 (newly added) -# 🆕 CONFIGURABLE FEE RATES -# All fields are optional - only specify ones you want to override +# FEE STRUCTURE: execution_fee + COGS + value_fee +# - execution_fee: flat per-run platform fee +# - COGS: per-node operational costs (gas, external APIs) — estimated automatically +# - value_fee: workflow-level % of tx value, classified by urgency/importance +# All fields optional — unset values use defaults shown below. fee_rates: - # Base fees (one-time per workflow) - defaults to 0.0 - base_fee_usd: 0.0 - - # Monitoring fees (per minute) - cost to monitor triggers - manual_monitoring_fee_usd_per_minute: 0.0 # Manual triggers free (default) - fixed_time_monitoring_fee_usd_per_minute: 0.000017 # ~$0.01/day (default) - cron_monitoring_fee_usd_per_minute: 0.000033 # ~$0.02/day (default) - block_monitoring_fee_usd_per_minute: 0.000033 # ~$0.02/day (default) - event_monitoring_fee_usd_per_minute: 0.000083 # ~$0.05/day (default) - - # Per-execution fees - cost for each trigger activation - manual_execution_fee_usd: 0.0 # Manual executions free (default) - scheduled_execution_fee_usd: 0.005 # $0.005 per scheduled execution (default) - block_execution_fee_usd: 0.01 # $0.01 per block trigger (default) - event_execution_fee_usd: 0.01 # $0.01 per event trigger (default) - - # Event monitoring scaling factors - additional costs for complex event monitoring - event_address_fee_usd_per_minute: 0.000008 # ~$0.005/day per address (default) - event_topic_fee_usd_per_minute: 0.000003 # ~$0.002/day per topic (default) + execution_fee_usd: 0.02 # Flat per-execution platform fee ($0.02 default) + tiers: + tier_1: 0.03 # Value-capture group 1 (0.03% of tx value) + tier_2: 0.09 # Value-capture group 2 (0.09% of tx value) + tier_3: 0.18 # Value-capture group 3 (0.18% of tx value) # Macro variables and secrets - Available globally to ALL workflows at runtime # Access in workflows via template syntax: {{apContext.configVars.SECRET_NAME}} diff --git a/core/config/config.go b/core/config/config.go index 04898c69..da9e3f0b 100644 --- a/core/config/config.go +++ b/core/config/config.go @@ -115,27 +115,16 @@ type Config struct { NotificationsSummary NotificationsSummaryConfig } -// FeeRatesConfig defines configurable pricing for different trigger types and operations +// FeeRatesConfig defines the fee structure for workflow execution. +// Three components: execution_fee (flat) + COGS (per-node) + value_fee (workflow-level tier %). type FeeRatesConfig struct { - // Base fees (one-time per workflow) - BaseFeeUSD float64 - - // Monitoring fees (per minute) - ManualMonitoringFeeUSDPerMinute float64 - FixedTimeMonitoringFeeUSDPerMinute float64 - CronMonitoringFeeUSDPerMinute float64 - BlockMonitoringFeeUSDPerMinute float64 - EventMonitoringFeeUSDPerMinute float64 - - // Per-execution fees - ManualExecutionFeeUSD float64 - ScheduledExecutionFeeUSD float64 - BlockExecutionFeeUSD float64 - EventExecutionFeeUSD float64 - - // Event monitoring scaling factors - EventAddressFeeUSDPerMinute float64 - EventTopicFeeUSDPerMinute float64 + // Flat per-execution platform fee (charged every run) + ExecutionFeeUSD float64 // Default: $0.02 + + // Value-capture tier percentages (% of tx value, workflow-level) + Tier1FeePercentage float64 // Default: 0.03% + Tier2FeePercentage float64 // Default: 0.09% + Tier3FeePercentage float64 // Default: 0.18% } // NotificationsSummaryConfig defines optional AI summarization settings for notifications. @@ -231,27 +220,15 @@ type ConfigRaw struct { // Moralis Web3 Data API key for token price lookup (optional) MoralisApiKey string `yaml:"moralis_api_key"` - // Fee rates configuration for task execution pricing + // Fee structure: execution_fee + COGS + value tiers + // Pointer fields: nil = use default, explicit 0.0 = free tier FeeRates struct { - // Base fees (one-time per workflow) - BaseFeeUSD float64 `yaml:"base_fee_usd"` - - // Monitoring fees (per minute) - ManualMonitoringFeeUSDPerMinute float64 `yaml:"manual_monitoring_fee_usd_per_minute"` - FixedTimeMonitoringFeeUSDPerMinute float64 `yaml:"fixed_time_monitoring_fee_usd_per_minute"` - CronMonitoringFeeUSDPerMinute float64 `yaml:"cron_monitoring_fee_usd_per_minute"` - BlockMonitoringFeeUSDPerMinute float64 `yaml:"block_monitoring_fee_usd_per_minute"` - EventMonitoringFeeUSDPerMinute float64 `yaml:"event_monitoring_fee_usd_per_minute"` - - // Per-execution fees - ManualExecutionFeeUSD float64 `yaml:"manual_execution_fee_usd"` - ScheduledExecutionFeeUSD float64 `yaml:"scheduled_execution_fee_usd"` - BlockExecutionFeeUSD float64 `yaml:"block_execution_fee_usd"` - EventExecutionFeeUSD float64 `yaml:"event_execution_fee_usd"` - - // Event monitoring scaling factors - EventAddressFeeUSDPerMinute float64 `yaml:"event_address_fee_usd_per_minute"` - EventTopicFeeUSDPerMinute float64 `yaml:"event_topic_fee_usd_per_minute"` + ExecutionFeeUSD *float64 `yaml:"execution_fee_usd"` // $0.02 default + Tiers struct { + Tier1 *float64 `yaml:"tier_1"` // 0.03% default + Tier2 *float64 `yaml:"tier_2"` // 0.09% default + Tier3 *float64 `yaml:"tier_3"` // 0.18% default + } `yaml:"tiers"` } `yaml:"fee_rates"` // Notifications configuration block @@ -559,81 +536,38 @@ func ReadYamlConfig(path string, o interface{}) error { return nil } -// loadFeeRatesFromConfig loads fee rates from configuration with fallback to hardcoded defaults -// This function works completely without YAML configuration - all fields are optional -// The hardcoded defaults match exactly what was previously in getDefaultAutomationRates() +// loadFeeRatesFromConfig loads fee config from YAML with fallback to defaults. +// Pointer fields distinguish "missing" (nil → use default) from explicit zero (0.0 → free tier). func loadFeeRatesFromConfig(configRates struct { - // Base fees (one-time per workflow) - BaseFeeUSD float64 `yaml:"base_fee_usd"` - - // Monitoring fees (per minute) - ManualMonitoringFeeUSDPerMinute float64 `yaml:"manual_monitoring_fee_usd_per_minute"` - FixedTimeMonitoringFeeUSDPerMinute float64 `yaml:"fixed_time_monitoring_fee_usd_per_minute"` - CronMonitoringFeeUSDPerMinute float64 `yaml:"cron_monitoring_fee_usd_per_minute"` - BlockMonitoringFeeUSDPerMinute float64 `yaml:"block_monitoring_fee_usd_per_minute"` - EventMonitoringFeeUSDPerMinute float64 `yaml:"event_monitoring_fee_usd_per_minute"` - - // Per-execution fees - ManualExecutionFeeUSD float64 `yaml:"manual_execution_fee_usd"` - ScheduledExecutionFeeUSD float64 `yaml:"scheduled_execution_fee_usd"` - BlockExecutionFeeUSD float64 `yaml:"block_execution_fee_usd"` - EventExecutionFeeUSD float64 `yaml:"event_execution_fee_usd"` - - // Event monitoring scaling factors - EventAddressFeeUSDPerMinute float64 `yaml:"event_address_fee_usd_per_minute"` - EventTopicFeeUSDPerMinute float64 `yaml:"event_topic_fee_usd_per_minute"` + ExecutionFeeUSD *float64 `yaml:"execution_fee_usd"` + Tiers struct { + Tier1 *float64 `yaml:"tier_1"` + Tier2 *float64 `yaml:"tier_2"` + Tier3 *float64 `yaml:"tier_3"` + } `yaml:"tiers"` }) *FeeRatesConfig { - // Helper function to get float64 from config with hardcoded default - // Uses the exact same defaults that were hardcoded in getDefaultAutomationRates() - getFloat64 := func(configValue, hardcodedDefault float64) float64 { - if configValue != 0.0 { - return configValue // Use YAML value if provided + getFloat64 := func(configValue *float64, hardcodedDefault float64) float64 { + if configValue != nil { + return *configValue } - return hardcodedDefault // Use hardcoded default (same as before) + return hardcodedDefault } return &FeeRatesConfig{ - // Base fees - exactly as before - BaseFeeUSD: getFloat64(configRates.BaseFeeUSD, 0.0), - - // Monitoring fees (per minute) - exactly as before - ManualMonitoringFeeUSDPerMinute: getFloat64(configRates.ManualMonitoringFeeUSDPerMinute, 0.0), - FixedTimeMonitoringFeeUSDPerMinute: getFloat64(configRates.FixedTimeMonitoringFeeUSDPerMinute, 0.000017), // ~$0.01/day - CronMonitoringFeeUSDPerMinute: getFloat64(configRates.CronMonitoringFeeUSDPerMinute, 0.000033), // ~$0.02/day - BlockMonitoringFeeUSDPerMinute: getFloat64(configRates.BlockMonitoringFeeUSDPerMinute, 0.000033), // ~$0.02/day - EventMonitoringFeeUSDPerMinute: getFloat64(configRates.EventMonitoringFeeUSDPerMinute, 0.000083), // ~$0.05/day base - - // Per-execution fees - exactly as before - ManualExecutionFeeUSD: getFloat64(configRates.ManualExecutionFeeUSD, 0.0), - ScheduledExecutionFeeUSD: getFloat64(configRates.ScheduledExecutionFeeUSD, 0.005), - BlockExecutionFeeUSD: getFloat64(configRates.BlockExecutionFeeUSD, 0.01), - EventExecutionFeeUSD: getFloat64(configRates.EventExecutionFeeUSD, 0.01), - - // Event monitoring scaling factors - exactly as before - EventAddressFeeUSDPerMinute: getFloat64(configRates.EventAddressFeeUSDPerMinute, 0.000008), // ~$0.005/day per address - EventTopicFeeUSDPerMinute: getFloat64(configRates.EventTopicFeeUSDPerMinute, 0.000003), // ~$0.002/day per topic group + ExecutionFeeUSD: getFloat64(configRates.ExecutionFeeUSD, 0.02), + Tier1FeePercentage: getFloat64(configRates.Tiers.Tier1, 0.03), + Tier2FeePercentage: getFloat64(configRates.Tiers.Tier2, 0.09), + Tier3FeePercentage: getFloat64(configRates.Tiers.Tier3, 0.18), } } -// GetDefaultFeeRatesConfig returns the default fee rates configuration -// This is useful for tests and as a reference for expected values +// GetDefaultFeeRatesConfig returns the default fee rates func GetDefaultFeeRatesConfig() *FeeRatesConfig { return &FeeRatesConfig{ - BaseFeeUSD: 0.0, - - ManualMonitoringFeeUSDPerMinute: 0.0, - FixedTimeMonitoringFeeUSDPerMinute: 0.000017, // ~$0.01/day - CronMonitoringFeeUSDPerMinute: 0.000033, // ~$0.02/day - BlockMonitoringFeeUSDPerMinute: 0.000033, // ~$0.02/day - EventMonitoringFeeUSDPerMinute: 0.000083, // ~$0.05/day base - - ManualExecutionFeeUSD: 0.0, - ScheduledExecutionFeeUSD: 0.005, - BlockExecutionFeeUSD: 0.01, - EventExecutionFeeUSD: 0.01, - - EventAddressFeeUSDPerMinute: 0.000008, // ~$0.005/day per address - EventTopicFeeUSDPerMinute: 0.000003, // ~$0.002/day per topic group + ExecutionFeeUSD: 0.02, + Tier1FeePercentage: 0.03, + Tier2FeePercentage: 0.09, + Tier3FeePercentage: 0.18, } } diff --git a/core/taskengine/engine.go b/core/taskengine/engine.go index 29e831e2..e6723908 100644 --- a/core/taskengine/engine.go +++ b/core/taskengine/engine.go @@ -2911,7 +2911,6 @@ func (n *Engine) SimulateTask(user *model.User, trigger *avsproto.TaskTrigger, n _, executionError, failedStepCount, resultStatus := vm.AnalyzeExecutionResult() // Step 11: Calculate total gas cost for the workflow - totalGasCost := vm.CalculateTotalGasCost() // Create execution result with proper status/error analysis execution := &avsproto.Execution{ @@ -2922,12 +2921,9 @@ func (n *Engine) SimulateTask(user *model.User, trigger *avsproto.TaskTrigger, n Error: executionError, // Comprehensive error message from failed steps Steps: vm.ExecutionLogs, // Now contains both trigger and node steps (including failed ones) Index: task.ExecutionCount, // Use current execution count for simulation (0-based) - TotalGasCost: totalGasCost, // Total gas cost for the entire workflow - AutomationFee: &avsproto.FeeAmount{ - NativeTokenAmount: "0", - NativeTokenSymbol: "", // Zero fee; symbol not applicable until automation fees are enabled - UsdAmount: "0", - }, + ExecutionFee: buildExecutionFee(n.config.FeeRates), + Cogs: buildCOGSFromSteps(vm.ExecutionLogs), + ValueFee: buildValueFee(vm.ExecutionLogs, n.config.FeeRates), } // Log execution status based on result type @@ -3267,16 +3263,14 @@ func (n *Engine) GetExecution(user *model.User, payload *avsproto.ExecutionReq) n.logger.Debug("🗂️ Returning pending execution", "task_id", payload.TaskId, "execution_id", payload.ExecutionId, "status", *execStatus, "index", pendingIndex) return &avsproto.Execution{ - Id: payload.ExecutionId, - Status: *execStatus, - StartAt: time.Now().UnixMilli(), // Approximate start time - Steps: []*avsproto.Execution_Step{}, // Empty steps for pending - Index: pendingIndex, // Use pre-assigned or newly assigned index - AutomationFee: &avsproto.FeeAmount{ - NativeTokenAmount: "0", - NativeTokenSymbol: "", // Zero fee; symbol not applicable until automation fees are enabled - UsdAmount: "0", - }, + Id: payload.ExecutionId, + Status: *execStatus, + StartAt: time.Now().UnixMilli(), // Approximate start time + Steps: []*avsproto.Execution_Step{}, // Empty steps for pending + Index: pendingIndex, // Use pre-assigned or newly assigned index + ExecutionFee: buildExecutionFee(n.config.FeeRates), // Known upfront + Cogs: []*avsproto.NodeCOGS{}, // Unknown until execution completes + ValueFee: nil, // Unknown until execution completes }, nil } diff --git a/core/taskengine/executor.go b/core/taskengine/executor.go index 0dca411e..2d1dcff6 100644 --- a/core/taskengine/executor.go +++ b/core/taskengine/executor.go @@ -559,19 +559,15 @@ func (x *TaskExecutor) RunTask(task *model.Task, queueData *QueueExecutionData) _, executionError, failedStepCount, resultStatus := vm.AnalyzeExecutionResult() // Calculate total gas cost for the workflow - totalGasCost := vm.CalculateTotalGasCost() // Update the execution record we created earlier with the final results execution.EndAt = t1.UnixMilli() execution.Status = convertToExecutionStatus(resultStatus) // Based on analysis of all steps execution.Error = executionError // Comprehensive error message from failed steps execution.Steps = vm.ExecutionLogs // Contains all steps including failed ones - execution.TotalGasCost = totalGasCost // Total gas cost for the entire workflow - execution.AutomationFee = &avsproto.FeeAmount{ - NativeTokenAmount: "0", - NativeTokenSymbol: "", // Zero fee; symbol not applicable until automation fees are enabled - UsdAmount: "0", - } + execution.ExecutionFee = buildExecutionFee(x.engine.config.FeeRates) + execution.Cogs = buildCOGSFromSteps(vm.ExecutionLogs) + execution.ValueFee = buildValueFee(vm.ExecutionLogs, x.engine.config.FeeRates) // Ensure no NaN/Inf sneak into protobuf Values (which reject them) sanitizeExecutionForPersistence(execution) diff --git a/core/taskengine/fee_estimator.go b/core/taskengine/fee_estimator.go index 890faef2..7e8a4b5a 100644 --- a/core/taskengine/fee_estimator.go +++ b/core/taskengine/fee_estimator.go @@ -4,12 +4,9 @@ import ( "context" "fmt" "math/big" - "strings" - "time" "github.com/AvaProtocol/EigenLayer-AVS/core/chainio/aa" "github.com/AvaProtocol/EigenLayer-AVS/core/config" - "github.com/AvaProtocol/EigenLayer-AVS/core/services" avsproto "github.com/AvaProtocol/EigenLayer-AVS/protobuf" sdklogging "github.com/Layr-Labs/eigensdk-go/logging" ethereum "github.com/ethereum/go-ethereum" @@ -28,9 +25,9 @@ type FeeEstimator struct { // Price service for USD conversion priceService PriceService - // Fee configuration - automationRates *AutomationFeeRates - discountRules *DiscountRules + // Node-tier fee configuration + feeRates *FeeRates + discountRules *DiscountRules } // PriceService interface for getting token prices @@ -39,27 +36,17 @@ type PriceService interface { GetNativeTokenSymbol(chainID int64) string } -// AutomationFeeRates defines pricing for different trigger types -type AutomationFeeRates struct { - // Base fees (one-time per workflow) - BaseFeeUSD float64 // $0.00 initially - - // Monitoring fees (per minute) - ManualMonitoringFeeUSDPerMinute float64 // $0.00 - FixedTimeMonitoringFeeUSDPerMinute float64 // $0.000017 (~$0.01/day) - CronMonitoringFeeUSDPerMinute float64 // $0.000033 (~$0.02/day) - BlockMonitoringFeeUSDPerMinute float64 // $0.000033 (~$0.02/day) - EventMonitoringFeeUSDPerMinute float64 // $0.000083 (~$0.05/day base) - - // Per-execution fees - ManualExecutionFeeUSD float64 // $0.00 - ScheduledExecutionFeeUSD float64 // $0.005 - BlockExecutionFeeUSD float64 // $0.01 - EventExecutionFeeUSD float64 // $0.01 - - // Event monitoring scaling factors - EventAddressFeeUSDPerMinute float64 // $0.000008 (~$0.005/day per address) - EventTopicFeeUSDPerMinute float64 // $0.000003 (~$0.002/day per topic group) +// FeeRates holds the fee configuration for the estimator. +// Three components: execution_fee (flat) + COGS (per-node) + value_fee (workflow-level tier %). +type FeeRates struct { + // Flat per-execution platform fee + ExecutionFeeUSD float64 // Default: $0.02 + + // Value-capture tier percentages (applied at workflow level, not per-node) + // Decision rule: failure → loss → Tier 3 | improves outcome → Tier 2 | simple → Tier 1 + Tier1FeePercentage float64 // Default: 0.03% + Tier2FeePercentage float64 // Default: 0.09% + Tier3FeePercentage float64 // Default: 0.18% } // DiscountRules defines promotional discount rules @@ -106,7 +93,7 @@ func NewFeeEstimator( smartWalletConfig: smartWalletConfig, chainID: 0, // Will be detected on first use priceService: priceService, - automationRates: getDefaultAutomationRates(), + feeRates: getDefaultFeeRates(), discountRules: getDefaultDiscountRules(), } } @@ -128,7 +115,7 @@ func NewFeeEstimatorWithConfig( smartWalletConfig: smartWalletConfig, chainID: 0, // Will be detected on first use priceService: priceService, - automationRates: convertFeeRatesConfigToAutomationRates(feeRatesConfig), + feeRates: convertFeeRatesConfig(feeRatesConfig), discountRules: getDefaultDiscountRules(), } } @@ -153,9 +140,10 @@ func (fe *FeeEstimator) getChainID(ctx context.Context) (int64, error) { return fe.chainID, nil } -// EstimateFees provides comprehensive fee estimation for a workflow +// EstimateFees provides per-execution fee estimation for a workflow. +// Response: execution_fee (USD) + cogs[] (WEI) + value_fee (PERCENTAGE) +// No totals — client computes. All fees are per-execution. func (fe *FeeEstimator) EstimateFees(ctx context.Context, req *avsproto.EstimateFeesReq) (*avsproto.EstimateFeesResp, error) { - // Detect chain ID first chainID, err := fe.getChainID(ctx) if err != nil { return &avsproto.EstimateFeesResp{ @@ -165,14 +153,14 @@ func (fe *FeeEstimator) EstimateFees(ctx context.Context, req *avsproto.Estimate }, nil } - fe.logger.Info("🔍 Starting comprehensive fee estimation", + fe.logger.Info("🔍 Starting fee estimation", "trigger_type", req.Trigger.Type.String(), "nodes_count", len(req.Nodes), "runner", req.Runner, "chain_id", chainID) - // Step 1: Resolve runner address and detect smart wallet creation needs - runnerAddress, smartWalletFee, err := fe.estimateSmartWalletCreation(ctx, req) + // Step 1: Resolve runner address for gas estimation + runnerAddress, walletCreationNeeded, walletCreationGasWei, err := fe.resolveRunnerAndWalletCreation(ctx, req) if err != nil { return &avsproto.EstimateFeesResp{ Success: false, @@ -181,85 +169,70 @@ func (fe *FeeEstimator) EstimateFees(ctx context.Context, req *avsproto.Estimate }, nil } - // Step 2: Estimate gas costs for all blockchain operations - gasFees, err := fe.estimateGasFees(ctx, req, runnerAddress) + // Step 2: COGS — per-node operational costs + cogs, err := fe.estimateCOGS(ctx, req, runnerAddress) if err != nil { return &avsproto.EstimateFeesResp{ Success: false, - Error: fmt.Sprintf("Failed to estimate gas fees: %v", err), + Error: fmt.Sprintf("Failed to estimate COGS: %v", err), ErrorCode: avsproto.ErrorCode_SIMULATION_ERROR, }, nil } - // Step 3: Calculate automation fees based on trigger type and duration - automationFee, err := fe.calculateAutomationFees(req) - if err != nil { - return &avsproto.EstimateFeesResp{ - Success: false, - Error: fmt.Sprintf("Failed to calculate automation fees: %v", err), - ErrorCode: avsproto.ErrorCode_INVALID_REQUEST, - }, nil + // Add wallet creation as a COGS entry if needed + if walletCreationNeeded { + cogs = append(cogs, &avsproto.NodeCOGS{ + NodeId: "_wallet_creation", + CostType: "wallet_creation", + Fee: &avsproto.Fee{Amount: walletCreationGasWei.String(), Unit: "WEI"}, + }) } - // Step 4: Calculate total fees - totalFees := fe.calculateTotalFees(gasFees, automationFee, smartWalletFee) - - // Step 5: Apply discounts and promotions - discounts, totalDiscounts, finalTotal := fe.applyDiscounts(gasFees, automationFee, smartWalletFee, totalFees) + // Step 3: Value fee — workflow-level classification + valueFee := fe.classifyWorkflowValue(req) - // Step 6: Get price data metadata - priceDataSource := "moralis" - priceDataAge := int64(0) - - // Get price data age if available - if moralisService, ok := fe.priceService.(*services.MoralisService); ok { - priceDataAge = moralisService.GetPriceDataAge(chainID) - priceDataSource = "moralis" - } else { - priceDataSource = "fallback" - } + nativeTokenSymbol := fe.priceService.GetNativeTokenSymbol(chainID) - fe.logger.Info("✅ Fee estimation completed successfully", - "total_gas_cost_wei", totalFees.NativeTokenAmount, - "total_usd", totalFees.UsdAmount, - "final_total_usd", finalTotal.UsdAmount) + fe.logger.Info("✅ Fee estimation completed", + "execution_fee_usd", fe.feeRates.ExecutionFeeUSD, + "cogs_count", len(cogs), + "value_fee_tier", valueFee.Tier.String()) return &avsproto.EstimateFeesResp{ - Success: true, - GasFees: gasFees, - AutomationFees: automationFee, - CreationFees: smartWalletFee, - TotalFees: totalFees, - Discounts: discounts, - TotalDiscounts: totalDiscounts, - FinalTotal: finalTotal, - EstimatedAt: time.Now().UnixMilli(), - ChainId: fmt.Sprintf("%d", chainID), - PriceDataSource: priceDataSource, - PriceDataAgeSeconds: priceDataAge, - Warnings: fe.generateWarnings(gasFees), - Recommendations: fe.generateRecommendations(req, gasFees, automationFee), + Success: true, + ChainId: fmt.Sprintf("%d", chainID), + NativeToken: &avsproto.NativeToken{ + Symbol: nativeTokenSymbol, + Decimals: 18, + }, + ExecutionFee: &avsproto.Fee{ + Amount: fmt.Sprintf("%.6f", fe.feeRates.ExecutionFeeUSD), + Unit: "USD", + }, + Cogs: cogs, + ValueFee: valueFee, + Discounts: []*avsproto.FeeDiscount{}, + PricingModel: "v1", + Warnings: fe.generateWarnings(cogs), }, nil } -// estimateSmartWalletCreation determines if smart wallet creation is needed and estimates costs -func (fe *FeeEstimator) estimateSmartWalletCreation(ctx context.Context, req *avsproto.EstimateFeesReq) (common.Address, *avsproto.SmartWalletCreationFee, error) { +// resolveRunnerAndWalletCreation resolves the runner address and checks if wallet creation is needed. +// Returns the runner address, whether creation is needed, and the estimated creation gas cost in wei. +func (fe *FeeEstimator) resolveRunnerAndWalletCreation(ctx context.Context, req *avsproto.EstimateFeesReq) (common.Address, bool, *big.Int, error) { var runnerAddress common.Address - var err error - // Try to get runner from request field first, then from input_variables if req.Runner != "" { if !common.IsHexAddress(req.Runner) { - return common.Address{}, nil, fmt.Errorf("invalid runner address format: %s", req.Runner) + return common.Address{}, false, nil, fmt.Errorf("invalid runner address format: %s", req.Runner) } runnerAddress = common.HexToAddress(req.Runner) } else { - // Try to extract from input_variables.settings.runner if settingsVal, ok := req.InputVariables["settings"]; ok { if settingsMap, ok := settingsVal.AsInterface().(map[string]interface{}); ok { if runner, ok := settingsMap["runner"].(string); ok && runner != "" { if !common.IsHexAddress(runner) { - return common.Address{}, nil, fmt.Errorf("invalid runner address in settings: %s", runner) + return common.Address{}, false, nil, fmt.Errorf("invalid runner address in settings: %s", runner) } runnerAddress = common.HexToAddress(runner) } @@ -267,65 +240,31 @@ func (fe *FeeEstimator) estimateSmartWalletCreation(ctx context.Context, req *av } } - // If no runner found, return error as we need it for gas estimation if (runnerAddress == common.Address{}) { - return common.Address{}, nil, fmt.Errorf("runner address not found in request or input_variables") + return common.Address{}, false, nil, fmt.Errorf("runner address not found in request or input_variables") } // Check if smart wallet already exists code, err := fe.ethClient.CodeAt(ctx, runnerAddress, nil) if err != nil { - fe.logger.Warn("Failed to check smart wallet deployment status", "address", runnerAddress.Hex(), "error", err) - // Continue with assumption that wallet exists to avoid blocking fee estimation - return runnerAddress, &avsproto.SmartWalletCreationFee{ - CreationRequired: false, - WalletAddress: runnerAddress.Hex(), - }, nil + return runnerAddress, false, nil, fmt.Errorf("failed to check smart wallet deployment status for %s: %w", runnerAddress.Hex(), err) } - creationRequired := len(code) == 0 - smartWalletFee := &avsproto.SmartWalletCreationFee{ - CreationRequired: creationRequired, - WalletAddress: runnerAddress.Hex(), + if len(code) > 0 { + return runnerAddress, false, nil, nil } - if creationRequired { - fe.logger.Info("Smart wallet creation required", "address", runnerAddress.Hex()) - - // Estimate gas for smart wallet creation - creationGas, gasPrice, err := fe.estimateWalletCreationGas(ctx, runnerAddress) - if err != nil { - fe.logger.Warn("Failed to estimate wallet creation gas", "error", err) - // Use fallback values - creationGas = big.NewInt(200000) // Conservative estimate - gasPrice = big.NewInt(int64(DefaultGasPrice)) - } - - creationCostWei := new(big.Int).Mul(creationGas, gasPrice) - creationFee, err := fe.convertToFeeAmount(creationCostWei) - if err != nil { - return common.Address{}, nil, fmt.Errorf("failed to convert creation fee: %w", err) - } - - // Recommend initial funding (creation cost + buffer for first execution) - fundingAmountWei := new(big.Int).Mul(creationCostWei, big.NewInt(2)) // 2x buffer - initialFunding, err := fe.convertToFeeAmount(fundingAmountWei) - if err != nil { - return common.Address{}, nil, fmt.Errorf("failed to convert initial funding amount: %w", err) - } - - smartWalletFee.CreationFee = creationFee - smartWalletFee.InitialFunding = initialFunding - } else { - fe.logger.Info("Smart wallet already exists", "address", runnerAddress.Hex()) - - // No creation needed, set zero fees - zeroFee, _ := fe.convertToFeeAmount(big.NewInt(0)) - smartWalletFee.CreationFee = zeroFee - smartWalletFee.InitialFunding = zeroFee + // Wallet creation needed — estimate gas + fe.logger.Info("Smart wallet creation required", "address", runnerAddress.Hex()) + creationGas, gasPrice, err := fe.estimateWalletCreationGas(ctx, runnerAddress) + if err != nil { + fe.logger.Warn("Failed to estimate wallet creation gas", "error", err) + creationGas = big.NewInt(200000) + gasPrice = big.NewInt(int64(DefaultGasPrice)) } - return runnerAddress, smartWalletFee, nil + creationCostWei := new(big.Int).Mul(creationGas, gasPrice) + return runnerAddress, true, creationCostWei, nil } // estimateWalletCreationGas estimates gas needed for smart wallet creation @@ -341,9 +280,6 @@ func (fe *FeeEstimator) estimateWalletCreationGas(ctx context.Context, walletAdd } // Build createAccount calldata using the factory ABI. - // We use walletAddress as a dummy owner with salt=0 to simulate a fresh deployment. - // The actual gas cost is dominated by proxy deployment and is constant regardless of owner/salt, - // as long as the resulting address has no deployed code (which we've already verified). factoryAddress := fe.smartWalletConfig.FactoryAddress initCodeHex, err := aa.GetInitCodeForFactory(walletAddress.Hex(), factoryAddress, big.NewInt(0)) if err != nil { @@ -382,26 +318,20 @@ func (fe *FeeEstimator) estimateWalletCreationGas(ctx context.Context, walletAdd return bufferedGas, gasPrice, nil } -// estimateGasFees estimates gas costs for all blockchain operations in the workflow -func (fe *FeeEstimator) estimateGasFees(ctx context.Context, req *avsproto.EstimateFeesReq, runnerAddress common.Address) (*avsproto.GasFeeBreakdown, error) { - fe.logger.Info("🔍 Estimating gas fees for workflow operations", "runner", runnerAddress.Hex()) +// estimateCOGS estimates cost of goods sold — per-node operational costs. +// Gas for on-chain nodes (contract_write, eth_transfer, loop). +// Future: external API costs for REST API nodes calling paid services. +func (fe *FeeEstimator) estimateCOGS(ctx context.Context, req *avsproto.EstimateFeesReq, runnerAddress common.Address) ([]*avsproto.NodeCOGS, error) { + fe.logger.Info("🔍 Estimating COGS for workflow", "runner", runnerAddress.Hex()) - var operations []*avsproto.GasOperationFee - totalGasUnits := big.NewInt(0) - totalGasCostWei := big.NewInt(0) - estimationAccurate := true - estimationMethod := "rpc_estimate" + var cogsList []*avsproto.NodeCOGS - // Get current gas price gasPrice, err := fe.ethClient.SuggestGasPrice(ctx) if err != nil { fe.logger.Warn("Failed to get current gas price, using fallback", "error", err) gasPrice = big.NewInt(int64(DefaultGasPrice)) - estimationAccurate = false - estimationMethod = "fallback" } - // Estimate gas for each node that requires blockchain operations for _, node := range req.Nodes { var gasResult *GasEstimationResult @@ -411,66 +341,26 @@ func (fe *FeeEstimator) estimateGasFees(ctx context.Context, req *avsproto.Estim case node.GetEthTransfer() != nil: gasResult = fe.estimateETHTransferGas(ctx, node, runnerAddress, gasPrice) case node.GetLoop() != nil: - // Handle loop nodes that might contain contract writes gasResult = fe.estimateLoopGas(ctx, node, runnerAddress, gasPrice) default: - // Skip nodes that don't require gas continue } if gasResult != nil { - if !gasResult.Success { - estimationAccurate = false - if gasResult.EstimationMethod != "rpc_estimate" { - estimationMethod = gasResult.EstimationMethod - } - } - - // Convert to FeeAmount - feeAmount, err := fe.convertToFeeAmount(gasResult.TotalCost) - if err != nil { - fe.logger.Warn("Failed to convert gas cost to fee amount", "error", err) - continue - } - - operation := &avsproto.GasOperationFee{ - OperationType: gasResult.OperationType, - NodeId: gasResult.NodeID, - MethodName: gasResult.MethodName, - Fee: feeAmount, - GasUnits: gasResult.GasUnits.String(), - } - - operations = append(operations, operation) - totalGasUnits.Add(totalGasUnits, gasResult.GasUnits) - totalGasCostWei.Add(totalGasCostWei, gasResult.TotalCost) + cogsList = append(cogsList, &avsproto.NodeCOGS{ + NodeId: gasResult.NodeID, + CostType: "gas", + Fee: &avsproto.Fee{Amount: gasResult.TotalCost.String(), Unit: "WEI"}, + GasUnits: gasResult.GasUnits.String(), + }) } } - // Convert total gas cost to FeeAmount - totalGasFees, err := fe.convertToFeeAmount(totalGasCostWei) - if err != nil { - return nil, fmt.Errorf("failed to convert total gas fees: %w", err) - } - - // Convert gas price to Gwei for display - gasPriceGwei := new(big.Float).Quo(new(big.Float).SetInt(gasPrice), big.NewFloat(1e9)) - - return &avsproto.GasFeeBreakdown{ - TotalGasFees: totalGasFees, - Operations: operations, - GasPriceGwei: fmt.Sprintf("%.2f", gasPriceGwei), - TotalGasUnits: totalGasUnits.String(), - EstimationAccurate: estimationAccurate, - EstimationMethod: estimationMethod, - }, nil + return cogsList, nil } -// Placeholder implementations for gas estimation methods +// Gas estimation methods for individual node types func (fe *FeeEstimator) estimateContractWriteGas(ctx context.Context, node *avsproto.TaskNode, runnerAddress common.Address, gasPrice *big.Int) *GasEstimationResult { - // TODO: Implement RPC-first gas estimation with Tenderly fallback - // For now, use conservative estimates - contractWrite := node.GetContractWrite() if contractWrite == nil { return nil @@ -480,7 +370,7 @@ func (fe *FeeEstimator) estimateContractWriteGas(ctx context.Context, node *avsp totalCost := new(big.Int).Mul(estimatedGas, gasPrice) methodName := "unknown" - if len(contractWrite.Config.MethodCalls) > 0 { + if contractWrite.Config != nil && len(contractWrite.Config.MethodCalls) > 0 { methodName = contractWrite.Config.MethodCalls[0].MethodName } @@ -497,7 +387,6 @@ func (fe *FeeEstimator) estimateContractWriteGas(ctx context.Context, node *avsp } func (fe *FeeEstimator) estimateETHTransferGas(ctx context.Context, node *avsproto.TaskNode, runnerAddress common.Address, gasPrice *big.Int) *GasEstimationResult { - // ETH transfers through smart wallets typically use more gas than direct transfers estimatedGas := big.NewInt(50000) // Conservative estimate for smart wallet ETH transfer totalCost := new(big.Int).Mul(estimatedGas, gasPrice) @@ -514,8 +403,6 @@ func (fe *FeeEstimator) estimateETHTransferGas(ctx context.Context, node *avspro } func (fe *FeeEstimator) estimateLoopGas(ctx context.Context, node *avsproto.TaskNode, runnerAddress common.Address, gasPrice *big.Int) *GasEstimationResult { - // TODO: Implement loop gas estimation based on loop contents - // For now, use a multiplier of the base contract write cost estimatedGas := big.NewInt(300000) // Conservative estimate for loop operations totalCost := new(big.Int).Mul(estimatedGas, gasPrice) @@ -531,492 +418,173 @@ func (fe *FeeEstimator) estimateLoopGas(ctx context.Context, node *avsproto.Task } } -// calculateAutomationFees calculates automation fees based on trigger type and duration -func (fe *FeeEstimator) calculateAutomationFees(req *avsproto.EstimateFeesReq) (*avsproto.AutomationFee, error) { - trigger := req.Trigger - triggerType := trigger.Type.String() - - // Calculate workflow duration in minutes - durationMinutes := int64(0) - if req.ExpireAt > req.CreatedAt { - durationMinutes = (req.ExpireAt - req.CreatedAt) / (1000 * 60) // Convert milliseconds to minutes - } - - // Estimate number of executions based on trigger type - estimatedExecutions := fe.estimateExecutionCount(trigger, durationMinutes, req.MaxExecution) - - // Calculate fees - baseFeeUSD := fe.automationRates.BaseFeeUSD - monitoringFeeUSD := fe.calculateMonitoringFee(trigger, durationMinutes) - executionFeeUSD := fe.calculateExecutionFee(trigger, estimatedExecutions) - - // Convert USD amounts to native token - baseFee, err := fe.convertUSDToFeeAmount(baseFeeUSD) - if err != nil { - return nil, fmt.Errorf("failed to convert base fee: %w", err) - } - - monitoringFee, err := fe.convertUSDToFeeAmount(monitoringFeeUSD) - if err != nil { - return nil, fmt.Errorf("failed to convert monitoring fee: %w", err) - } - - executionFee, err := fe.convertUSDToFeeAmount(executionFeeUSD) - if err != nil { - return nil, fmt.Errorf("failed to convert execution fee: %w", err) - } - - feeCalculationMethod := fe.buildFeeCalculationDescription(trigger, durationMinutes, estimatedExecutions) - - return &avsproto.AutomationFee{ - BaseFee: baseFee, - MonitoringFee: monitoringFee, - ExecutionFee: executionFee, - TriggerType: triggerType, - EstimatedExecutions: estimatedExecutions, - DurationMinutes: durationMinutes, - FeeCalculationMethod: feeCalculationMethod, - }, nil -} - -// Helper methods for automation fee calculation -func (fe *FeeEstimator) estimateExecutionCount(trigger *avsproto.TaskTrigger, durationMinutes, maxExecution int64) int64 { - switch trigger.Type { - case avsproto.TriggerType_TRIGGER_TYPE_MANUAL: - if maxExecution > 0 { - return maxExecution - } - return 1 // Default assumption for manual triggers - - case avsproto.TriggerType_TRIGGER_TYPE_FIXED_TIME: - return 1 // Fixed time triggers execute once - - case avsproto.TriggerType_TRIGGER_TYPE_CRON: - // TODO: Parse cron expression to calculate execution frequency - // For now, assume every hour as default - executions := durationMinutes / 60 - if maxExecution > 0 && executions > maxExecution { - return maxExecution - } - return executions - - case avsproto.TriggerType_TRIGGER_TYPE_BLOCK: - // TODO: Calculate based on block interval - // For now, assume every 10 blocks (approximately every 2 minutes for 12s block time) - executions := durationMinutes / 2 - if maxExecution > 0 && executions > maxExecution { - return maxExecution - } - return executions - - case avsproto.TriggerType_TRIGGER_TYPE_EVENT: - // Event triggers are unpredictable, use conservative estimate - // Assume 1 execution per day as default - executions := durationMinutes / (24 * 60) - if executions < 1 { - executions = 1 - } - if maxExecution > 0 && executions > maxExecution { - return maxExecution +// classifyWorkflowValue determines the value-capture tier for the entire workflow. +// This is a single workflow-level classification, not per-node. +// +// Decision rule: "If this workflow fails or is delayed, does the user lose money immediately?" +// - YES → Tier 3 +// - NO but improves outcome → Tier 2 +// - Simple execution → Tier 1 +// +// V1: rule-based, defaults to Tier 1 if workflow has on-chain nodes, UNSPECIFIED otherwise. +// V2: LLM-based classification analyzing workflow purpose and node composition. +func (fe *FeeEstimator) classifyWorkflowValue(req *avsproto.EstimateFeesReq) *avsproto.ValueFee { + hasOnChainNodes := false + for _, node := range req.Nodes { + if isOnChainNode(node) { + hasOnChainNodes = true + break } - return executions - - default: - return 1 } -} - -func (fe *FeeEstimator) calculateMonitoringFee(trigger *avsproto.TaskTrigger, durationMinutes int64) float64 { - rates := fe.automationRates - - switch trigger.Type { - case avsproto.TriggerType_TRIGGER_TYPE_MANUAL: - return float64(durationMinutes) * rates.ManualMonitoringFeeUSDPerMinute - - case avsproto.TriggerType_TRIGGER_TYPE_FIXED_TIME: - return float64(durationMinutes) * rates.FixedTimeMonitoringFeeUSDPerMinute - - case avsproto.TriggerType_TRIGGER_TYPE_CRON: - return float64(durationMinutes) * rates.CronMonitoringFeeUSDPerMinute - - case avsproto.TriggerType_TRIGGER_TYPE_BLOCK: - return float64(durationMinutes) * rates.BlockMonitoringFeeUSDPerMinute - - case avsproto.TriggerType_TRIGGER_TYPE_EVENT: - baseFee := float64(durationMinutes) * rates.EventMonitoringFeeUSDPerMinute - // Add scaling fees based on addresses and topics - if eventTrigger := trigger.GetEvent(); eventTrigger != nil { - // Add fee per query configuration - if config := eventTrigger.GetConfig(); config != nil { - for _, query := range config.GetQueries() { - // Add fee per address - addressCount := len(query.GetAddresses()) - addressFee := float64(durationMinutes) * rates.EventAddressFeeUSDPerMinute * float64(addressCount) - baseFee += addressFee - - // Add fee per topic group - topicGroups := len(query.GetTopics()) - topicFee := float64(durationMinutes) * rates.EventTopicFeeUSDPerMinute * float64(topicGroups) - baseFee += topicFee - } - } + if !hasOnChainNodes { + return &avsproto.ValueFee{ + Fee: &avsproto.Fee{Amount: "0", Unit: "PERCENTAGE"}, + Tier: avsproto.ExecutionTier_EXECUTION_TIER_UNSPECIFIED, + ValueBase: "", + ClassificationMethod: "rule_based", + Confidence: 1.0, + Reason: "Workflow has no on-chain execution nodes — no value-capture fee", } - - return baseFee - - default: - return 0.0 } -} - -func (fe *FeeEstimator) calculateExecutionFee(trigger *avsproto.TaskTrigger, estimatedExecutions int64) float64 { - rates := fe.automationRates - - switch trigger.Type { - case avsproto.TriggerType_TRIGGER_TYPE_MANUAL: - return float64(estimatedExecutions) * rates.ManualExecutionFeeUSD - - case avsproto.TriggerType_TRIGGER_TYPE_FIXED_TIME, avsproto.TriggerType_TRIGGER_TYPE_CRON: - return float64(estimatedExecutions) * rates.ScheduledExecutionFeeUSD - - case avsproto.TriggerType_TRIGGER_TYPE_BLOCK: - return float64(estimatedExecutions) * rates.BlockExecutionFeeUSD - - case avsproto.TriggerType_TRIGGER_TYPE_EVENT: - return float64(estimatedExecutions) * rates.EventExecutionFeeUSD - default: - return 0.0 + // V1: all workflows with on-chain nodes default to Tier 1 + // V2: LLM will analyze workflow purpose (e.g., AAVE repay → Tier 3) + return &avsproto.ValueFee{ + Fee: &avsproto.Fee{Amount: fmt.Sprintf("%.2f", fe.feeRates.Tier1FeePercentage), Unit: "PERCENTAGE"}, + Tier: avsproto.ExecutionTier_EXECUTION_TIER_1, + ValueBase: "input_token_value", + ClassificationMethod: "rule_based", + Confidence: 1.0, + Reason: "V1 default: workflow contains on-chain execution nodes", } } -func (fe *FeeEstimator) buildFeeCalculationDescription(trigger *avsproto.TaskTrigger, durationMinutes, estimatedExecutions int64) string { - triggerType := strings.ToLower(trigger.Type.String()[13:]) // Remove "TRIGGER_TYPE_" prefix - - return fmt.Sprintf("Calculated for %s trigger over %d minutes with %d estimated executions", - triggerType, durationMinutes, estimatedExecutions) +// isOnChainNode returns true if the node performs on-chain transactions +func isOnChainNode(node *avsproto.TaskNode) bool { + return node.GetEthTransfer() != nil || + node.GetContractWrite() != nil || + node.GetLoop() != nil } -// calculateTotalFees sums all fee components -func (fe *FeeEstimator) calculateTotalFees(gasFees *avsproto.GasFeeBreakdown, automationFee *avsproto.AutomationFee, smartWalletFee *avsproto.SmartWalletCreationFee) *avsproto.FeeAmount { - // Sum all fee components in wei - totalWei := big.NewInt(0) - - // Add gas fees - if gasFees != nil && gasFees.TotalGasFees != nil { - if gasWei, ok := new(big.Int).SetString(gasFees.TotalGasFees.NativeTokenAmount, 10); ok { - totalWei.Add(totalWei, gasWei) - } - } - - // Add automation fees - if automationFee != nil { - if automationFee.BaseFee != nil { - if baseWei, ok := new(big.Int).SetString(automationFee.BaseFee.NativeTokenAmount, 10); ok { - totalWei.Add(totalWei, baseWei) - } - } - if automationFee.MonitoringFee != nil { - if monitoringWei, ok := new(big.Int).SetString(automationFee.MonitoringFee.NativeTokenAmount, 10); ok { - totalWei.Add(totalWei, monitoringWei) - } - } - if automationFee.ExecutionFee != nil { - if executionWei, ok := new(big.Int).SetString(automationFee.ExecutionFee.NativeTokenAmount, 10); ok { - totalWei.Add(totalWei, executionWei) - } - } - } - - // Add smart wallet creation fees - if smartWalletFee != nil && smartWalletFee.CreationFee != nil { - if creationWei, ok := new(big.Int).SetString(smartWalletFee.CreationFee.NativeTokenAmount, 10); ok { - totalWei.Add(totalWei, creationWei) - } - } - - // Convert to FeeAmount - totalFees, err := fe.convertToFeeAmount(totalWei) - if err != nil { - fe.logger.Warn("Failed to convert total fees", "error", err) - // Return zero fees on error - zeroFees, _ := fe.convertToFeeAmount(big.NewInt(0)) - return zeroFees - } - - return totalFees -} - -// applyDiscounts applies promotional discounts to the calculated fees -func (fe *FeeEstimator) applyDiscounts(gasFees *avsproto.GasFeeBreakdown, automationFee *avsproto.AutomationFee, smartWalletFee *avsproto.SmartWalletCreationFee, totalFees *avsproto.FeeAmount) ([]*avsproto.FeeDiscount, *avsproto.FeeAmount, *avsproto.FeeAmount) { - var discounts []*avsproto.FeeDiscount - totalDiscountUSD := 0.0 - - // Apply beta program discount (100% off automation fees) - if fe.discountRules.BetaProgramAutomationDiscount > 0 { - automationDiscountUSD := 0.0 - if automationFee != nil { - // Sum automation fee components - if automationFee.BaseFee != nil { - if baseUSD, err := parseFloat(automationFee.BaseFee.UsdAmount); err == nil { - automationDiscountUSD += baseUSD - } - } - if automationFee.MonitoringFee != nil { - if monitoringUSD, err := parseFloat(automationFee.MonitoringFee.UsdAmount); err == nil { - automationDiscountUSD += monitoringUSD - } - } - if automationFee.ExecutionFee != nil { - if executionUSD, err := parseFloat(automationFee.ExecutionFee.UsdAmount); err == nil { - automationDiscountUSD += executionUSD - } - } - } - - if automationDiscountUSD > 0 { - discountAmount := automationDiscountUSD * fe.discountRules.BetaProgramAutomationDiscount - totalDiscountUSD += discountAmount - - discountFeeAmount, err := fe.convertUSDToFeeAmount(discountAmount) - if err == nil { - discounts = append(discounts, &avsproto.FeeDiscount{ - DiscountType: "beta_program", - DiscountName: "Beta Program Launch Discount", - AppliesTo: "automation_fees", - DiscountPercentage: float32(fe.discountRules.BetaProgramAutomationDiscount * 100), - DiscountAmount: discountFeeAmount, - ExpiryDate: "2025-12-31T23:59:59Z", // TODO: Make configurable - Terms: "100% off automation fees during beta program", - }) - } - } - } - - // Convert total discounts to FeeAmount - totalDiscounts, err := fe.convertUSDToFeeAmount(totalDiscountUSD) - if err != nil { - fe.logger.Warn("Failed to convert total discounts", "error", err) - totalDiscounts, _ = fe.convertToFeeAmount(big.NewInt(0)) - } - - // Calculate final total (total fees - discounts) - totalFeesWei, _ := new(big.Int).SetString(totalFees.NativeTokenAmount, 10) - totalDiscountsWei, _ := new(big.Int).SetString(totalDiscounts.NativeTokenAmount, 10) - finalTotalWei := new(big.Int).Sub(totalFeesWei, totalDiscountsWei) +// generateWarnings generates warnings about fee estimation accuracy +func (fe *FeeEstimator) generateWarnings(cogs []*avsproto.NodeCOGS) []string { + var warnings []string - // Ensure final total is not negative - if finalTotalWei.Cmp(big.NewInt(0)) < 0 { - finalTotalWei = big.NewInt(0) + if len(cogs) > 0 { + warnings = append(warnings, "Gas estimates use conservative fallback values. Actual costs may vary.") } - finalTotal, err := fe.convertToFeeAmount(finalTotalWei) - if err != nil { - fe.logger.Warn("Failed to convert final total", "error", err) - finalTotal = totalFees // Fallback to original total - } - - return discounts, totalDiscounts, finalTotal + return warnings } -// Helper method to parse float from string -func parseFloat(s string) (float64, error) { - // Remove any currency formatting and parse - cleaned := strings.ReplaceAll(s, "$", "") - cleaned = strings.ReplaceAll(cleaned, ",", "") - var result float64 - n, err := fmt.Sscanf(cleaned, "%f", &result) - if err != nil { - return 0, err - } - if n != 1 { - return 0, fmt.Errorf("unable to parse float from string: %s", s) +// Default configuration +func getDefaultFeeRates() *FeeRates { + return &FeeRates{ + ExecutionFeeUSD: 0.02, + Tier1FeePercentage: 0.03, + Tier2FeePercentage: 0.09, + Tier3FeePercentage: 0.18, } - return result, nil } -// generateWarnings generates warnings about fee estimation accuracy -func (fe *FeeEstimator) generateWarnings(gasFees *avsproto.GasFeeBreakdown) []string { - var warnings []string +func getDefaultDiscountRules() *DiscountRules { + return &DiscountRules{ + BetaProgramAutomationDiscount: 1.0, // 100% off automation fees + BetaProgramGasDiscount: 0.0, // 0% off gas fees - if gasFees != nil && !gasFees.EstimationAccurate { - warnings = append(warnings, "Gas estimation used fallback values due to RPC unavailability. Actual costs may vary.") - } + NewUserAutomationDiscount: 0.8, // 80% off automation fees + NewUserGasDiscount: 0.0, // 0% off gas fees - if gasFees != nil && gasFees.EstimationMethod == "fallback" { - warnings = append(warnings, "Conservative gas estimates used. Consider testing with smaller amounts first.") + VolumeDiscountThreshold: 10, // 10+ workflows + VolumeDiscountPercentage: 0.1, // 10% discount } - - return warnings } -// generateRecommendations generates cost optimization recommendations -func (fe *FeeEstimator) generateRecommendations(req *avsproto.EstimateFeesReq, gasFees *avsproto.GasFeeBreakdown, automationFee *avsproto.AutomationFee) []string { - var recommendations []string - - // Check if workflow duration is very long - if req.ExpireAt > req.CreatedAt { - durationMinutes := (req.ExpireAt - req.CreatedAt) / (1000 * 60) - if durationMinutes > 30*24*60 { // More than 30 days - recommendations = append(recommendations, "Consider shorter workflow durations to reduce monitoring costs.") - } - } - - // Check for high execution count - if automationFee != nil && automationFee.EstimatedExecutions > 1000 { - recommendations = append(recommendations, "High execution count detected. Consider optimizing trigger conditions to reduce costs.") +// buildExecutionFee returns the execution fee from config (or default). +func buildExecutionFee(feeRatesConfig *config.FeeRatesConfig) *avsproto.Fee { + rates := convertFeeRatesConfig(feeRatesConfig) + return &avsproto.Fee{ + Amount: fmt.Sprintf("%.6f", rates.ExecutionFeeUSD), + Unit: "USD", } - - // Check trigger type optimization - if req.Trigger.Type == avsproto.TriggerType_TRIGGER_TYPE_EVENT { - recommendations = append(recommendations, "Event triggers have higher monitoring costs. Consider manual triggers if suitable for your use case.") - } - - return recommendations } -// Utility methods for fee conversion -func (fe *FeeEstimator) convertToFeeAmount(weiAmount *big.Int) (*avsproto.FeeAmount, error) { - // Use cached chain ID if available, otherwise detect it - chainID := fe.chainID - if chainID == 0 { - // Try to detect chain ID, but don't fail if context is not available - // This is a fallback for cases where convertToFeeAmount is called without context - chainIDResult, err := fe.ethClient.ChainID(context.Background()) - if err == nil { - chainID = chainIDResult.Int64() - fe.chainID = chainID // Cache for next time - } else { - // Use a reasonable default - chainID = 1 // Ethereum mainnet as fallback +// buildValueFee classifies the workflow and returns the value fee. +// Uses the task's nodes to determine if on-chain execution is present. +func buildValueFee(steps []*avsproto.Execution_Step, feeRatesConfig *config.FeeRatesConfig) *avsproto.ValueFee { + rates := convertFeeRatesConfig(feeRatesConfig) + + hasOnChainSteps := false + for _, step := range steps { + stepType := step.Type + if stepType == avsproto.NodeType_NODE_TYPE_CONTRACT_WRITE.String() || + stepType == avsproto.NodeType_NODE_TYPE_ETH_TRANSFER.String() || + stepType == avsproto.NodeType_NODE_TYPE_LOOP.String() { + hasOnChainSteps = true + break } } - nativeTokenSymbol := fe.priceService.GetNativeTokenSymbol(chainID) - - // Convert wei to USD - nativeTokenPriceUSD, err := fe.priceService.GetNativeTokenPriceUSD(chainID) - if err != nil { - fe.logger.Warn("Failed to get native token price", "error", err) - nativeTokenPriceUSD = big.NewFloat(2500) // Fallback price - } - - // Convert wei to token amount (divide by 10^18) - weiFloat := new(big.Float).SetInt(weiAmount) - tokenAmount := new(big.Float).Quo(weiFloat, big.NewFloat(1e18)) - - // Calculate USD amount - usdAmount := new(big.Float).Mul(tokenAmount, nativeTokenPriceUSD) - - return &avsproto.FeeAmount{ - NativeTokenAmount: weiAmount.String(), - NativeTokenSymbol: nativeTokenSymbol, - UsdAmount: fmt.Sprintf("%.6f", usdAmount), - ApTokenAmount: "0", // TODO: Implement AP token conversion - }, nil -} - -func (fe *FeeEstimator) convertUSDToFeeAmount(usdAmount float64) (*avsproto.FeeAmount, error) { - // Use cached chain ID if available, otherwise detect it - chainID := fe.chainID - if chainID == 0 { - // Try to detect chain ID, but don't fail if context is not available - chainIDResult, err := fe.ethClient.ChainID(context.Background()) - if err == nil { - chainID = chainIDResult.Int64() - fe.chainID = chainID // Cache for next time - } else { - // Use a reasonable default - chainID = 1 // Ethereum mainnet as fallback + if !hasOnChainSteps { + return &avsproto.ValueFee{ + Fee: &avsproto.Fee{Amount: "0", Unit: "PERCENTAGE"}, + Tier: avsproto.ExecutionTier_EXECUTION_TIER_UNSPECIFIED, + ClassificationMethod: "rule_based", + Confidence: 1.0, + Reason: "Workflow has no on-chain execution nodes", } } - nativeTokenSymbol := fe.priceService.GetNativeTokenSymbol(chainID) - - // Get native token price - nativeTokenPriceUSD, err := fe.priceService.GetNativeTokenPriceUSD(chainID) - if err != nil { - fe.logger.Warn("Failed to get native token price", "error", err) - nativeTokenPriceUSD = big.NewFloat(2500) // Fallback price + return &avsproto.ValueFee{ + Fee: &avsproto.Fee{Amount: fmt.Sprintf("%.2f", rates.Tier1FeePercentage), Unit: "PERCENTAGE"}, + Tier: avsproto.ExecutionTier_EXECUTION_TIER_1, + ValueBase: "input_token_value", + ClassificationMethod: "rule_based", + Confidence: 1.0, + Reason: "V1 default: workflow contains on-chain execution nodes", } - - // Convert USD to token amount - usdFloat := big.NewFloat(usdAmount) - tokenAmount := new(big.Float).Quo(usdFloat, nativeTokenPriceUSD) - - // Convert to wei (multiply by 10^18) - weiFloat := new(big.Float).Mul(tokenAmount, big.NewFloat(1e18)) - weiAmount, _ := weiFloat.Int(nil) - - return &avsproto.FeeAmount{ - NativeTokenAmount: weiAmount.String(), - NativeTokenSymbol: nativeTokenSymbol, - UsdAmount: fmt.Sprintf("%.6f", usdAmount), - ApTokenAmount: "0", // TODO: Implement AP token conversion - }, nil } -// Default configuration -func getDefaultAutomationRates() *AutomationFeeRates { - return &AutomationFeeRates{ - BaseFeeUSD: 0.0, +// buildCOGSFromSteps converts per-step gas data from execution logs into NodeCOGS entries. +// This is used after execution to build the actual COGS from real gas receipts. +func buildCOGSFromSteps(steps []*avsproto.Execution_Step) []*avsproto.NodeCOGS { + var cogsList []*avsproto.NodeCOGS - ManualMonitoringFeeUSDPerMinute: 0.0, - FixedTimeMonitoringFeeUSDPerMinute: 0.000017, // ~$0.01/day - CronMonitoringFeeUSDPerMinute: 0.000033, // ~$0.02/day - BlockMonitoringFeeUSDPerMinute: 0.000033, // ~$0.02/day - EventMonitoringFeeUSDPerMinute: 0.000083, // ~$0.05/day base + for _, step := range steps { + // Only on-chain steps have gas data + if step.TotalGasCost == "" || step.TotalGasCost == "0" { + continue + } - ManualExecutionFeeUSD: 0.0, - ScheduledExecutionFeeUSD: 0.005, - BlockExecutionFeeUSD: 0.01, - EventExecutionFeeUSD: 0.01, + stepType := step.Type + if stepType != avsproto.NodeType_NODE_TYPE_CONTRACT_WRITE.String() && + stepType != avsproto.NodeType_NODE_TYPE_ETH_TRANSFER.String() && + stepType != avsproto.NodeType_NODE_TYPE_LOOP.String() { + continue + } - EventAddressFeeUSDPerMinute: 0.000008, // ~$0.005/day per address - EventTopicFeeUSDPerMinute: 0.000003, // ~$0.002/day per topic group + cogsList = append(cogsList, &avsproto.NodeCOGS{ + NodeId: step.Id, + CostType: "gas", + Fee: &avsproto.Fee{Amount: step.TotalGasCost, Unit: "WEI"}, + GasUnits: step.GasUsed, + }) } -} - -func getDefaultDiscountRules() *DiscountRules { - return &DiscountRules{ - BetaProgramAutomationDiscount: 1.0, // 100% off automation fees - BetaProgramGasDiscount: 0.0, // 0% off gas fees - - NewUserAutomationDiscount: 0.8, // 80% off automation fees - NewUserGasDiscount: 0.0, // 0% off gas fees - VolumeDiscountThreshold: 10, // 10+ workflows - VolumeDiscountPercentage: 0.1, // 10% discount - } + return cogsList } -// convertFeeRatesConfigToAutomationRates converts configuration-based fee rates to internal automation rates -func convertFeeRatesConfigToAutomationRates(configRates *config.FeeRatesConfig) *AutomationFeeRates { +// convertFeeRatesConfig converts configuration-based fee rates to internal tier rates +func convertFeeRatesConfig(configRates *config.FeeRatesConfig) *FeeRates { if configRates == nil { - // Fallback to defaults if no configuration provided - return getDefaultAutomationRates() - } - - return &AutomationFeeRates{ - // Base fees - BaseFeeUSD: configRates.BaseFeeUSD, - - // Monitoring fees (per minute) - ManualMonitoringFeeUSDPerMinute: configRates.ManualMonitoringFeeUSDPerMinute, - FixedTimeMonitoringFeeUSDPerMinute: configRates.FixedTimeMonitoringFeeUSDPerMinute, - CronMonitoringFeeUSDPerMinute: configRates.CronMonitoringFeeUSDPerMinute, - BlockMonitoringFeeUSDPerMinute: configRates.BlockMonitoringFeeUSDPerMinute, - EventMonitoringFeeUSDPerMinute: configRates.EventMonitoringFeeUSDPerMinute, - - // Per-execution fees - ManualExecutionFeeUSD: configRates.ManualExecutionFeeUSD, - ScheduledExecutionFeeUSD: configRates.ScheduledExecutionFeeUSD, - BlockExecutionFeeUSD: configRates.BlockExecutionFeeUSD, - EventExecutionFeeUSD: configRates.EventExecutionFeeUSD, - - // Event monitoring scaling factors - EventAddressFeeUSDPerMinute: configRates.EventAddressFeeUSDPerMinute, - EventTopicFeeUSDPerMinute: configRates.EventTopicFeeUSDPerMinute, + return getDefaultFeeRates() + } + + return &FeeRates{ + ExecutionFeeUSD: configRates.ExecutionFeeUSD, + Tier1FeePercentage: configRates.Tier1FeePercentage, + Tier2FeePercentage: configRates.Tier2FeePercentage, + Tier3FeePercentage: configRates.Tier3FeePercentage, } } diff --git a/core/taskengine/fee_estimator_test.go b/core/taskengine/fee_estimator_test.go index a79757c4..8572edaf 100644 --- a/core/taskengine/fee_estimator_test.go +++ b/core/taskengine/fee_estimator_test.go @@ -5,122 +5,301 @@ import ( "math/big" "testing" - "github.com/AvaProtocol/EigenLayer-AVS/core/services" + "github.com/AvaProtocol/EigenLayer-AVS/core/config" "github.com/AvaProtocol/EigenLayer-AVS/core/testutil" + avsproto "github.com/AvaProtocol/EigenLayer-AVS/protobuf" sdklogging "github.com/Layr-Labs/eigensdk-go/logging" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -// mockPriceService implements PriceService interface for testing type mockPriceService struct{} -func (m *mockPriceService) GetNativeTokenPriceUSD(chainID int64) (*big.Float, error) { - // Return different prices based on chain ID to verify it's being passed correctly +func (mock *mockPriceService) GetNativeTokenPriceUSD(chainID int64) (*big.Float, error) { switch chainID { - case 1: // Ethereum mainnet - return big.NewFloat(3000.0), nil - case 11155111: // Sepolia - return big.NewFloat(2500.0), nil - case 8453: // Base mainnet - return big.NewFloat(3000.0), nil - case 84532: // Base Sepolia + case 11155111: return big.NewFloat(2500.0), nil default: - return big.NewFloat(2000.0), nil // Fallback + return big.NewFloat(2000.0), nil } } -func (m *mockPriceService) GetNativeTokenSymbol(chainID int64) string { - return "ETH" // All supported chains use ETH +func (mock *mockPriceService) GetNativeTokenSymbol(chainID int64) string { + return "ETH" } func TestFeeEstimator_ChainIDDetection(t *testing.T) { logger, err := sdklogging.NewZapLogger(sdklogging.Development) - require.NoError(t, err, "Failed to create logger") + require.NoError(t, err) smartWalletConfig := testutil.GetTestSmartWalletConfig() - - // Create eth client from test config RPC ethClient := testutil.GetRpcClient() defer ethClient.Close() - // Create fee estimator with mock price service - feeEstimator := NewFeeEstimator( - logger, - ethClient, - nil, // No tenderly client needed for this test - smartWalletConfig, - &mockPriceService{}, - ) + feeEstimator := NewFeeEstimator(logger, ethClient, nil, smartWalletConfig, &mockPriceService{}) - // Verify chain ID starts as 0 (not detected yet) - assert.Equal(t, int64(0), feeEstimator.chainID, "Chain ID should be 0 initially") + assert.Equal(t, int64(0), feeEstimator.chainID) - // Test chain ID detection ctx := context.Background() detectedChainID, err := feeEstimator.getChainID(ctx) - require.NoError(t, err, "Failed to detect chain ID") - assert.True(t, detectedChainID > 0, "Detected chain ID should be positive") - assert.Equal(t, detectedChainID, feeEstimator.chainID, "Chain ID should be cached") + require.NoError(t, err) + assert.True(t, detectedChainID > 0) + assert.Equal(t, detectedChainID, feeEstimator.chainID) +} + +func TestIsOnChainNode(t *testing.T) { + assert.True(t, isOnChainNode(&avsproto.TaskNode{TaskType: &avsproto.TaskNode_EthTransfer{EthTransfer: &avsproto.ETHTransferNode{}}})) + assert.True(t, isOnChainNode(&avsproto.TaskNode{TaskType: &avsproto.TaskNode_ContractWrite{ContractWrite: &avsproto.ContractWriteNode{}}})) + assert.True(t, isOnChainNode(&avsproto.TaskNode{TaskType: &avsproto.TaskNode_Loop{Loop: &avsproto.LoopNode{}}})) + + assert.False(t, isOnChainNode(&avsproto.TaskNode{TaskType: &avsproto.TaskNode_ContractRead{ContractRead: &avsproto.ContractReadNode{}}})) + assert.False(t, isOnChainNode(&avsproto.TaskNode{TaskType: &avsproto.TaskNode_RestApi{RestApi: &avsproto.RestAPINode{}}})) + assert.False(t, isOnChainNode(&avsproto.TaskNode{TaskType: &avsproto.TaskNode_Branch{Branch: &avsproto.BranchNode{}}})) + assert.False(t, isOnChainNode(&avsproto.TaskNode{})) +} - // Test that subsequent calls return cached value - cachedChainID, err := feeEstimator.getChainID(ctx) - require.NoError(t, err, "Failed to get cached chain ID") - assert.Equal(t, detectedChainID, cachedChainID, "Cached chain ID should match") +func TestDefaultFeeRates(t *testing.T) { + rates := getDefaultFeeRates() - // Test utility methods use correct chain ID - testAmount := big.NewInt(1000000000000000000) // 1 ETH in wei - feeAmount, err := feeEstimator.convertToFeeAmount(testAmount) - require.NoError(t, err, "Failed to convert fee amount") + assert.Equal(t, 0.02, rates.ExecutionFeeUSD) + assert.Equal(t, 0.03, rates.Tier1FeePercentage) + assert.Equal(t, 0.09, rates.Tier2FeePercentage) + assert.Equal(t, 0.18, rates.Tier3FeePercentage) +} - assert.Equal(t, "ETH", feeAmount.NativeTokenSymbol, "Symbol should be ETH") - assert.Equal(t, testAmount.String(), feeAmount.NativeTokenAmount, "Native token amount should match input") +func TestConvertFeeRatesConfig(t *testing.T) { + t.Run("nil config returns defaults", func(t *testing.T) { + rates := convertFeeRatesConfig(nil) + defaults := getDefaultFeeRates() + assert.Equal(t, defaults, rates) + }) - // Verify USD amount is non-empty (the mock returns a price for any chain) - assert.NotEmpty(t, feeAmount.UsdAmount, "USD amount should be set") + t.Run("custom config is applied", func(t *testing.T) { + customConfig := &config.FeeRatesConfig{ + ExecutionFeeUSD: 0.05, + Tier1FeePercentage: 0.10, + Tier2FeePercentage: 0.20, + Tier3FeePercentage: 0.50, + } + rates := convertFeeRatesConfig(customConfig) + assert.Equal(t, 0.05, rates.ExecutionFeeUSD) + assert.Equal(t, 0.10, rates.Tier1FeePercentage) + }) } -func TestFeeEstimator_MoralisServiceIntegration(t *testing.T) { +func TestClassifyWorkflowValue_WithOnChainNodes(t *testing.T) { logger, err := sdklogging.NewZapLogger(sdklogging.Development) - require.NoError(t, err, "Failed to create logger") + require.NoError(t, err) smartWalletConfig := testutil.GetTestSmartWalletConfig() + ethClient := testutil.GetRpcClient() + defer ethClient.Close() + + feeEstimator := NewFeeEstimator(logger, ethClient, nil, smartWalletConfig, &mockPriceService{}) - // Connect using test config RPC + req := &avsproto.EstimateFeesReq{ + Nodes: []*avsproto.TaskNode{ + {Id: "read1", TaskType: &avsproto.TaskNode_ContractRead{ContractRead: &avsproto.ContractReadNode{}}}, + {Id: "write1", TaskType: &avsproto.TaskNode_ContractWrite{ContractWrite: &avsproto.ContractWriteNode{}}}, + }, + } + + valueFee := feeEstimator.classifyWorkflowValue(req) + + assert.Equal(t, avsproto.ExecutionTier_EXECUTION_TIER_1, valueFee.Tier) + require.NotNil(t, valueFee.Fee) + assert.Equal(t, "0.03", valueFee.Fee.Amount) + assert.Equal(t, "PERCENTAGE", valueFee.Fee.Unit) + assert.Equal(t, "input_token_value", valueFee.ValueBase) + assert.Equal(t, "rule_based", valueFee.ClassificationMethod) + assert.Equal(t, float32(1.0), valueFee.Confidence) +} + +func TestClassifyWorkflowValue_NoOnChainNodes(t *testing.T) { + logger, err := sdklogging.NewZapLogger(sdklogging.Development) + require.NoError(t, err) + + smartWalletConfig := testutil.GetTestSmartWalletConfig() ethClient := testutil.GetRpcClient() defer ethClient.Close() - // Create Moralis service (will use fallback pricing if no API key) - moralisService := services.GetMoralisService("", logger) + feeEstimator := NewFeeEstimator(logger, ethClient, nil, smartWalletConfig, &mockPriceService{}) - // Create fee estimator - feeEstimator := NewFeeEstimator( - logger, - ethClient, - nil, - smartWalletConfig, - moralisService, - ) + req := &avsproto.EstimateFeesReq{ + Nodes: []*avsproto.TaskNode{ + {Id: "read1", TaskType: &avsproto.TaskNode_ContractRead{ContractRead: &avsproto.ContractReadNode{}}}, + {Id: "branch1", TaskType: &avsproto.TaskNode_Branch{Branch: &avsproto.BranchNode{}}}, + }, + } - ctx := context.Background() + valueFee := feeEstimator.classifyWorkflowValue(req) + + assert.Equal(t, avsproto.ExecutionTier_EXECUTION_TIER_UNSPECIFIED, valueFee.Tier) + assert.Equal(t, "0", valueFee.Fee.Amount) + assert.Equal(t, "", valueFee.ValueBase) +} + +func TestEstimateCOGS_MixedNodes(t *testing.T) { + logger, err := sdklogging.NewZapLogger(sdklogging.Development) + require.NoError(t, err) + + smartWalletConfig := testutil.GetTestSmartWalletConfig() + ethClient := testutil.GetRpcClient() + defer ethClient.Close() + + feeEstimator := NewFeeEstimator(logger, ethClient, nil, smartWalletConfig, &mockPriceService{}) + + req := &avsproto.EstimateFeesReq{ + Nodes: []*avsproto.TaskNode{ + {Id: "read1", TaskType: &avsproto.TaskNode_ContractRead{ContractRead: &avsproto.ContractReadNode{}}}, + {Id: "branch1", TaskType: &avsproto.TaskNode_Branch{Branch: &avsproto.BranchNode{}}}, + {Id: "write1", TaskType: &avsproto.TaskNode_ContractWrite{ContractWrite: &avsproto.ContractWriteNode{}}}, + {Id: "transfer1", TaskType: &avsproto.TaskNode_EthTransfer{EthTransfer: &avsproto.ETHTransferNode{}}}, + }, + } + + _, err = feeEstimator.getChainID(context.Background()) + require.NoError(t, err) + + runnerAddr := testutil.GetTestSmartWalletConfig().ControllerAddress + cogs, err := feeEstimator.estimateCOGS(context.Background(), req, runnerAddr) + require.NoError(t, err) + + // Only on-chain nodes should have COGS entries + assert.Len(t, cogs, 2) + assert.Equal(t, "write1", cogs[0].NodeId) + assert.Equal(t, "gas", cogs[0].CostType) + assert.Equal(t, "WEI", cogs[0].Fee.Unit) + assert.Equal(t, "transfer1", cogs[1].NodeId) + + // Fee amount should be a non-zero WEI string + weiAmount, ok := new(big.Int).SetString(cogs[0].Fee.Amount, 10) + assert.True(t, ok) + assert.True(t, weiAmount.Cmp(big.NewInt(0)) > 0) +} + +func TestEstimateCOGS_NoOnChainNodes(t *testing.T) { + logger, err := sdklogging.NewZapLogger(sdklogging.Development) + require.NoError(t, err) + + smartWalletConfig := testutil.GetTestSmartWalletConfig() + ethClient := testutil.GetRpcClient() + defer ethClient.Close() + + feeEstimator := NewFeeEstimator(logger, ethClient, nil, smartWalletConfig, &mockPriceService{}) + + req := &avsproto.EstimateFeesReq{ + Nodes: []*avsproto.TaskNode{ + {Id: "read1", TaskType: &avsproto.TaskNode_ContractRead{ContractRead: &avsproto.ContractReadNode{}}}, + {Id: "api1", TaskType: &avsproto.TaskNode_RestApi{RestApi: &avsproto.RestAPINode{}}}, + }, + } + + _, err = feeEstimator.getChainID(context.Background()) + require.NoError(t, err) + + runnerAddr := testutil.GetTestSmartWalletConfig().ControllerAddress + cogs, err := feeEstimator.estimateCOGS(context.Background(), req, runnerAddr) + require.NoError(t, err) + + assert.Len(t, cogs, 0, "Non on-chain nodes should produce no COGS") +} + +func TestCustomConfig_AffectsAllFees(t *testing.T) { + logger, err := sdklogging.NewZapLogger(sdklogging.Development) + require.NoError(t, err) + + smartWalletConfig := testutil.GetTestSmartWalletConfig() + ethClient := testutil.GetRpcClient() + defer ethClient.Close() + + customConfig := &config.FeeRatesConfig{ + ExecutionFeeUSD: 0.05, + Tier1FeePercentage: 0.10, + Tier2FeePercentage: 0.20, + Tier3FeePercentage: 0.50, + } + + feeEstimator := NewFeeEstimatorWithConfig(logger, ethClient, nil, smartWalletConfig, &mockPriceService{}, customConfig) + + // Verify execution fee uses custom rate + assert.Equal(t, 0.05, feeEstimator.feeRates.ExecutionFeeUSD) + + // Verify value fee uses custom tier rate + req := &avsproto.EstimateFeesReq{ + Nodes: []*avsproto.TaskNode{ + {Id: "w1", TaskType: &avsproto.TaskNode_ContractWrite{ContractWrite: &avsproto.ContractWriteNode{}}}, + }, + } + valueFee := feeEstimator.classifyWorkflowValue(req) + assert.Equal(t, "0.10", valueFee.Fee.Amount, "Should use custom Tier 1 rate") +} + +func TestEstimateFeesResp_Format(t *testing.T) { + logger, err := sdklogging.NewZapLogger(sdklogging.Development) + require.NoError(t, err) + + smartWalletConfig := testutil.GetTestSmartWalletConfig() + ethClient := testutil.GetRpcClient() + defer ethClient.Close() + + feeEstimator := NewFeeEstimator(logger, ethClient, nil, smartWalletConfig, &mockPriceService{}) + + req := &avsproto.EstimateFeesReq{ + Trigger: &avsproto.TaskTrigger{Type: avsproto.TriggerType_TRIGGER_TYPE_MANUAL}, + Nodes: []*avsproto.TaskNode{ + {Id: "read1", TaskType: &avsproto.TaskNode_ContractRead{ContractRead: &avsproto.ContractReadNode{}}}, + {Id: "write1", TaskType: &avsproto.TaskNode_ContractWrite{ContractWrite: &avsproto.ContractWriteNode{}}}, + }, + Runner: "0x0000000000000000000000000000000000000001", + CreatedAt: 1000000, + ExpireAt: 2000000, + MaxExecution: 1, + } + + resp, err := feeEstimator.EstimateFees(context.Background(), req) + require.NoError(t, err) + assert.True(t, resp.Success) + + // execution_fee is Fee{amount, unit} + require.NotNil(t, resp.ExecutionFee) + assert.Equal(t, "USD", resp.ExecutionFee.Unit) + assert.Equal(t, "0.020000", resp.ExecutionFee.Amount) + + // native_token is set + require.NotNil(t, resp.NativeToken) + assert.Equal(t, "ETH", resp.NativeToken.Symbol) + assert.Equal(t, int32(18), resp.NativeToken.Decimals) + + // cogs entries use Fee{amount: WEI} + // May include wallet_creation COGS if runner address doesn't exist on-chain + assert.GreaterOrEqual(t, len(resp.Cogs), 1, "Should have at least contract_write COGS") + + // Find the contract_write COGS entry + var writeCogs *avsproto.NodeCOGS + for _, cogsEntry := range resp.Cogs { + if cogsEntry.NodeId == "write1" { + writeCogs = cogsEntry + break + } + } + require.NotNil(t, writeCogs, "Should have COGS for write1") + assert.Equal(t, "gas", writeCogs.CostType) + assert.Equal(t, "WEI", writeCogs.Fee.Unit) - // Test chain ID detection - chainID, err := feeEstimator.getChainID(ctx) - require.NoError(t, err, "Failed to detect chain ID") - assert.True(t, chainID > 0, "Should detect a valid chain ID") + // value_fee uses Fee{amount: PERCENTAGE} + require.NotNil(t, resp.ValueFee) + assert.Equal(t, "PERCENTAGE", resp.ValueFee.Fee.Unit) + assert.Equal(t, "0.03", resp.ValueFee.Fee.Amount) + assert.Equal(t, "input_token_value", resp.ValueFee.ValueBase) - // Test Moralis service integration for price data - price, err := moralisService.GetNativeTokenPriceUSD(chainID) - require.NoError(t, err, "Failed to get ETH price") - assert.True(t, price.Cmp(big.NewFloat(0)) > 0, "Price should be positive") + // discounts is empty array (not nil) + assert.NotNil(t, resp.Discounts) + assert.Len(t, resp.Discounts, 0) - symbol := moralisService.GetNativeTokenSymbol(chainID) - assert.Equal(t, "ETH", symbol, "Symbol should be ETH") + // pricing_model set + assert.Equal(t, "v1", resp.PricingModel) - // Test supported chains - supportedChains := moralisService.GetSupportedChains() - assert.Contains(t, supportedChains, int64(1), "Should support Ethereum mainnet") - assert.Contains(t, supportedChains, int64(8453), "Should support Base mainnet") - assert.Len(t, supportedChains, 4, "Should support exactly 4 chains (ETH + Base mainnet/testnet)") + // chain_id set + assert.NotEmpty(t, resp.ChainId) } diff --git a/core/taskengine/gas_cost_tracking_test.go b/core/taskengine/gas_cost_tracking_test.go index f1cffe31..442061c6 100644 --- a/core/taskengine/gas_cost_tracking_test.go +++ b/core/taskengine/gas_cost_tracking_test.go @@ -187,40 +187,40 @@ func TestGasCostExtractionFromTenderly(t *testing.T) { }) } -func TestWorkflowLevelGasCostAggregation(t *testing.T) { - t.Run("Execution message should have TotalGasCost field", func(t *testing.T) { - execution := &avsproto.Execution{ - Id: "execution_123", - TotalGasCost: "250000000000000", // Total gas cost for workflow - Steps: []*avsproto.Execution_Step{ - { - Id: "step1", - Type: avsproto.NodeType_NODE_TYPE_CONTRACT_WRITE.String(), - TotalGasCost: "150000000000000", - }, - { - Id: "step2", - Type: avsproto.NodeType_NODE_TYPE_ETH_TRANSFER.String(), - TotalGasCost: "100000000000000", - }, +func TestBuildCOGSFromSteps(t *testing.T) { + t.Run("builds COGS from step-level gas data", func(t *testing.T) { + steps := []*avsproto.Execution_Step{ + { + Id: "step1", + Type: avsproto.NodeType_NODE_TYPE_CONTRACT_WRITE.String(), + GasUsed: "100000", + TotalGasCost: "150000000000000", + }, + { + Id: "step2", + Type: avsproto.NodeType_NODE_TYPE_ETH_TRANSFER.String(), + GasUsed: "50000", + TotalGasCost: "100000000000000", + }, + { + Id: "step3", + Type: avsproto.NodeType_NODE_TYPE_CONTRACT_READ.String(), + TotalGasCost: "", // Non on-chain — no gas }, } - // Verify the total matches the sum of steps - totalFromSteps := new(big.Int) - for _, step := range execution.Steps { - if step.TotalGasCost != "" { - stepCost, ok := new(big.Int).SetString(step.TotalGasCost, 10) - if ok { - totalFromSteps.Add(totalFromSteps, stepCost) - } - } - } + cogs := buildCOGSFromSteps(steps) - actualTotal, ok := new(big.Int).SetString(execution.TotalGasCost, 10) - require.True(t, ok, "Should parse total gas cost") + // Only on-chain steps with gas data should produce COGS + assert.Len(t, cogs, 2) + assert.Equal(t, "step1", cogs[0].NodeId) + assert.Equal(t, "gas", cogs[0].CostType) + assert.Equal(t, "150000000000000", cogs[0].Fee.Amount) + assert.Equal(t, "WEI", cogs[0].Fee.Unit) + assert.Equal(t, "100000", cogs[0].GasUnits) - assert.Equal(t, totalFromSteps.String(), actualTotal.String(), "Total gas cost should equal sum of step costs") + assert.Equal(t, "step2", cogs[1].NodeId) + assert.Equal(t, "100000000000000", cogs[1].Fee.Amount) }) } diff --git a/docs/API_PROTOCOL_COMPARISON.md b/docs/API_PROTOCOL_COMPARISON.md new file mode 100644 index 00000000..9fe46389 --- /dev/null +++ b/docs/API_PROTOCOL_COMPARISON.md @@ -0,0 +1,146 @@ +# API Protocol Comparison: Partner-Facing API + +This document evaluates protocol options for exposing the AVS aggregator's functionality to partner applications and the Studio frontend. + +--- + +## Current Architecture + +``` +Partner App → Widget/iframe → Studio REST API → SDK (gRPC) → AVS Aggregator + ↕ + Operators (gRPC streaming) +``` + +- **Internal**: Operators communicate with the aggregator over gRPC (protobuf). This handles task streaming, result reporting, and real-time state sync. +- **External**: Studio (Next.js) proxies browser/partner requests to the aggregator via `@avaprotocol/sdk-js`, which speaks gRPC internally. +- **Partners and browsers never call gRPC directly.** + +--- + +## Options Evaluated + +### 1. gRPC / Protobuf (current internal protocol) + +Binary RPC framework using HTTP/2 and protocol buffers for serialization. Already used for operator ↔ aggregator communication. + +**Strengths:** +- Schema-first with strong type safety and codegen for most languages +- Efficient binary encoding, lower bandwidth than JSON +- First-class streaming (server, client, bidirectional) — critical for operator task sync +- Backward compatibility via proto field numbering + +**Weaknesses for partner use:** +- No native browser support — requires grpc-web + an Envoy or Connect proxy +- Partners need the protobuf toolchain and generated client stubs to integrate +- Binary on the wire — cannot inspect with curl, browser devtools, or Postman +- Smaller ecosystem for API gateways, rate limiters, WAFs, and monitoring +- gRPC status codes are less familiar than HTTP status codes to most developers +- Error messages are opaque without proto definitions + +### 2. REST (JSON over HTTP) — recommended for partner API + +Standard request/response over HTTP using JSON. The most widely adopted API style. + +**Strengths:** +- Universal — any language with HTTP and JSON works, zero client libraries required +- First API call possible with a single curl command +- Directly inspectable in browser devtools, Postman, and logging tools +- Massive ecosystem: every API gateway, CDN, WAF, rate limiter, and monitoring tool supports it natively +- OpenAPI/Swagger provides interactive documentation and try-it-out UIs +- HTTP status codes are universally understood +- Easy to version with URL prefixes (`/v1/`, `/v2/`) + +**Weaknesses:** +- No built-in streaming (possible via SSE or WebSockets, but not native) +- No schema enforcement without additional tooling (OpenAPI, Zod, etc.) +- Slightly higher bandwidth than binary protobuf (negligible for this use case) + +### 3. Connect (connectrpc.com) + +Wire-compatible with gRPC but also supports plain JSON over HTTP. Built by the Buf team. + +**Strengths:** +- Reuses existing `.proto` definitions — no schema rewrite +- Supports `fetch()` in browsers without a proxy +- Streaming support over standard HTTP +- Incremental migration from existing gRPC server + +**Weaknesses:** +- Still proto-first — partners need to understand protobuf schema concepts +- Smaller community and tooling ecosystem than REST +- Less familiar to most web developers than plain REST +- Documentation tooling less mature than OpenAPI/Swagger + +### 4. GraphQL + +Query language that lets clients request exactly the fields they need. + +**Strengths:** +- Flexible queries — client picks fields, avoids over/under-fetching +- Strong typing via schema +- Good tooling (`gqlgen` for Go, Apollo/urql for frontend) +- Single endpoint simplifies routing + +**Weaknesses:** +- Overkill when the API surface is well-defined RPCs (which ours is) +- Adds complexity: query parsing, resolver architecture, N+1 prevention +- Caching is harder than REST (no HTTP cache semantics by default) +- Partners must learn GraphQL query syntax + +--- + +## Side-by-Side: gRPC vs REST for Partner API + +| Concern | gRPC / Protobuf | REST (JSON/HTTP) | +| ---------------------- | ------------------------------------------------ | ------------------------------------------------- | +| **Partner onboarding** | High — proto toolchain, codegen, language support | Low — `curl` or `fetch`, any language | +| **First API call** | Minutes to hours (setup proto, generate client) | Seconds (`curl -X POST ...`) | +| **Browser support** | No (needs grpc-web + proxy) | Native `fetch()`, works everywhere | +| **Debugging** | Binary — needs grpcurl or generated client | curl, Postman, browser devtools | +| **Documentation** | Proto files + separate docs site | OpenAPI/Swagger with interactive try-it-out | +| **Type safety** | Excellent — schema-first codegen | Good with OpenAPI — codegen available but optional | +| **Performance** | Better — binary encoding, HTTP/2 multiplexing | Good enough for partner request volumes | +| **Streaming** | First-class (server, client, bidirectional) | SSE or WebSockets (sufficient for notifications) | +| **Versioning** | Proto field numbering | URL prefix (`/v1/`, `/v2/`) — universally understood | +| **Error handling** | gRPC status codes (less familiar) | HTTP status codes — universally understood | +| **Ecosystem** | Smaller — interceptors for auth, rate limiting | Massive — every gateway, WAF, CDN supports it | +| **API key auth** | Custom gRPC metadata interceptors | Standard `X-API-Key` header | +| **Rate limiting** | Custom interceptor or sidecar proxy | Off-the-shelf middleware (Redis, API gateway) | + +--- + +## Decision + +**REST for all partner-facing and browser-facing endpoints. gRPC remains for internal operator communication.** + +### Rationale + +1. **Audience**: Partners are app developers (web, mobile, backend). REST is the lingua franca — no onboarding friction, no toolchain requirements. + +2. **Browser constraint**: The Studio frontend and embedded widget cannot call gRPC natively. REST eliminates the need for a grpc-web proxy layer. + +3. **Operational simplicity**: REST works with standard infrastructure — API gateways, CDNs, rate limiters, WAFs, logging, and monitoring all support it out of the box. + +4. **Performance is not the bottleneck**: Partner API traffic is low-frequency CRUD (create automation, check status, cancel). The performance gap between JSON and protobuf is irrelevant at these volumes. The performance-sensitive path (operator task streaming) stays on gRPC. + +5. **Industry standard**: Google, Stripe, Cloudflare, and most cloud providers use this exact pattern — gRPC internally, REST for the public API. + +### What stays on gRPC + +| Path | Protocol | Why | +| ----------------------------- | -------- | ------------------------------------------------ | +| Operator ↔ Aggregator | gRPC | Streaming task sync, binary efficiency, real-time | +| Studio SDK → Aggregator | gRPC | SDK already speaks gRPC, server-to-server | +| Partner App → Studio | REST | Browser-compatible, zero-friction onboarding | +| Widget Frontend → Studio | REST | Browser `fetch()`, no proxy needed | + +### Implementation path + +Studio already acts as the REST proxy layer (see `EXECUTION_CHECKOUT.md`). The partner API extends this with: +- Versioned routes (`/api/v1/executions`) +- API key authentication (`X-API-Key` header) +- Rate limiting (per-key token bucket) +- OpenAPI spec for documentation and client codegen + +See `EXECUTION_CHECKOUT.md` → "Partner API: Auth, Rate Limiting, and Versioning" for implementation details. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 00000000..a929e5c9 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,277 @@ +# Ava Protocol AVS — Architecture & Implementation Design + +## Overview + +Ava Protocol AVS is a decentralized workflow automation system built on EigenLayer. Users define no-code workflows (trigger → nodes → actions) that execute automatically when on-chain or off-chain conditions are met. The system uses ERC-6900 modular smart wallets for on-chain execution and ERC-4337 account abstraction for gasless operation. + +## System Architecture + +``` +┌──────────────────────────────────────────────────────────┐ +│ USER / CLIENT (Studio) │ +└────────────────────────┬─────────────────────────────────┘ + │ gRPC + ▼ +┌──────────────────────────────────────────────────────────┐ +│ AGGREGATOR (Port 2206) │ +│ │ +│ RPC Server ──── Engine ──── Queue + Worker │ +│ │ │ │ │ +│ │ ├─ Task CRUD ├─ Async job execution │ +│ │ ├─ Trigger └─ BadgerDB-backed │ +│ │ │ distribution │ +│ │ ├─ Operator Fee Estimator │ +│ │ │ management (node-tier pricing) │ +│ │ └─ Dedup │ +│ │ │ +│ Storage: BadgerDB (tasks, executions, wallets) │ +└────────────────────┬─────────────────────────────────────┘ + │ gRPC SyncMessages stream + ▼ +┌──────────────────────────────────────────────────────────┐ +│ OPERATOR(S) (N instances) │ +│ │ +│ Worker Loop ──── Trigger Engines ──── RPC Clients │ +│ │ │ │ │ +│ │ ┌────┴────┐ Blockchain RPC │ +│ │ │ Block │ Tenderly │ +│ │ │ Event │ Bundler │ +│ │ │ Cron │ │ +│ │ │ Manual │ │ +│ │ └─────────┘ │ +│ │ │ +│ Task Executor ──── VM (Goja JS) ──── Node Runners │ +│ │ │ +│ Smart Wallet (ERC-6900) │ +│ │ │ +│ ERC-4337 Bundler → Blockchain │ +└──────────────────────────────────────────────────────────┘ +``` + +## Package Structure + +``` +├── aggregator/ Aggregator service: RPC server, operator pool, auth +├── operator/ Operator service: worker loop, trigger monitoring, message processing +├── core/ +│ ├── taskengine/ Execution engine, VM, node runners, fee estimation +│ ├── apqueue/ BadgerDB-backed async job queue +│ ├── chainio/aa/ Account abstraction (ERC-6900 wallet, UserOp construction) +│ ├── config/ YAML configuration loading and defaults +│ ├── auth/ JWT-based authentication +│ ├── services/ Shared services (Moralis price feeds) +│ └── backup/migrator/ Database schema migrations +├── protobuf/ gRPC service and message definitions +├── storage/ BadgerDB persistence wrapper +├── model/ Data models (Task, User, Secret) +├── pkg/ Utility packages (erc20, erc4337, eip1559, graphql) +├── contracts/ Smart contract Go bindings +├── cmd/ CLI entry points (aggregator, operator, register) +└── config/ YAML configuration files per environment +``` + +## Core Subsystems + +### 1. Aggregator + +Entry: `aggregator/aggregator.go` → `Start(ctx)` + +Startup sequence: +1. Load YAML config, init ETH RPC + chain ID +2. Open BadgerDB, run migrations +3. Start task engine (load existing tasks into memory) +4. Start gRPC server (port 2206) +5. Start HTTP telemetry server + +Key files: +- `aggregator/rpc_server.go` — gRPC handlers: CreateTask, DeleteTask, ListTasks, SimulateTask, EstimateFees, GetWallet, etc. +- `aggregator/pool.go` — Operator connection pool management +- `aggregator/auth.go` — JWT auth with EIP-191 signature verification + +### 2. Operator + +Entry: `operator/operator.go` → `runWorkLoop(ctx)` + +The operator connects to the aggregator via gRPC `SyncMessages` stream and: +1. Receives task assignments (trigger configs to monitor) +2. Monitors triggers locally (block headers, contract events, cron schedules) +3. Sends `NotifyTriggers` RPC when conditions are met +4. Handles `ImmediateTrigger` messages for manual execution + +Key files: +- `operator/worker_loop.go` — Main event loop, trigger monitoring +- `operator/process_message.go` — Handle SyncMessages commands (monitor, disable, delete, immediate) + +Connection resilience: exponential backoff on disconnect (1s → 60s max), error debouncing (same error logged max every 3 min). + +### 3. Task Engine + +Core: `core/taskengine/engine.go` + +The engine manages the full task lifecycle: + +``` +CreateTask → Store in BadgerDB → Distribute triggers to operators + ↓ + Operator monitors trigger + ↓ + NotifyTriggers (with dedup) + ↓ + Queue execution job + ↓ + TaskExecutor.RunTask() + ↓ + Store execution result +``` + +Key responsibilities: +- **Task CRUD** — create, list, enable/disable, delete +- **Operator management** — streaming assignments, heartbeat tracking +- **Trigger distribution** — batch-send tasks to operators every 3s +- **Deduplication** — `trigger_request_id` tracking prevents duplicate executions +- **Execution queueing** — async job queue backed by BadgerDB + +### 4. Trigger System + +Location: `core/taskengine/trigger/` + +Five trigger types: +| Type | How it works | Dedup key | +|------|-------------|-----------| +| Manual | User/webhook-initiated | N/A | +| FixedTime | One-time at specified epoch | Timestamp | +| Cron | Recurring schedule (cron syntax) | Timestamp | +| Block | Every N blocks | Block number | +| Event | Contract event log matching + conditions | `tx_hash:log_index` | + +Event triggers support: +- Multi-address, multi-topic filtering +- ABI-based log decoding +- Condition evaluation on decoded fields (gt, lt, eq, etc.) +- Token metadata enrichment (decimals, symbol via Moralis) +- Safety limits: max events per block, overload reporting to aggregator + +### 5. Node Execution + +Location: `core/taskengine/vm.go` + `vm_runner_*.go` + +The VM executes workflow nodes sequentially using the Goja JavaScript runtime. Each node has access to previous node outputs via `node_name.data`. + +Node types and their runners: +| Node | Runner | Purpose | +|------|--------|---------| +| `eth_transfer` | `vm_runner_eth_transfer.go` | Send ETH/ERC20 via smart wallet | +| `contract_write` | `vm_runner_contract_write.go` | Write to contracts (UserOp submission) | +| `contract_read` | `vm_runner_contract_read.go` | Query contract state | +| `rest_api` | `vm_runner_rest.go` | HTTP API calls (SendGrid, external services) | +| `custom_code` | `vm_runner_custom_code.go` | Arbitrary JavaScript execution | +| `graphql_query` | `vm_runner_graphql.go` | GraphQL queries | +| `branch` | `vm_runner_branch.go` | Conditional routing | +| `filter` | `vm_runner_filter.go` | Array filtering | +| `loop` | Loop helpers | Iterate over arrays (sequential or parallel) | +| `balance` | Balance runner | Fetch wallet token balances | + +Execution flow for on-chain writes: +1. Resolve variables and template expressions +2. Encode contract call data (ABI encoding) +3. Simulate via Tenderly (optional dry-run) +4. Construct ERC-4337 UserOperation +5. Submit to bundler → EntryPoint → blockchain + +### 6. Smart Wallet System + +Location: `core/chainio/aa/` + +Uses ERC-6900 modular accounts with ERC-4337 account abstraction: +- Factory deploys per-user smart wallets: `factory.createAccount(owner, salt)` +- Operator constructs UserOperations with calldata for contract writes +- Bundler aggregates and submits UserOps to the EntryPoint contract +- Optional paymaster covers gas costs + +### 7. Fee Estimation + +Location: `core/taskengine/fee_estimator.go` + +Three fee components, each with its own unit via `Fee{amount, unit}`: + +| Component | Unit | Purpose | +|-----------|------|---------| +| `execution_fee` | USD | Flat $0.02 per-run platform fee | +| `cogs[]` | WEI | Per-node gas costs via `estimateCOGS()` | +| `value_fee` | PERCENTAGE | Workflow-level value capture via `classifyWorkflowValue()` | + +Value-capture tiers (pure pricing groups, V1 defaults all to Tier 1): + +| Tier | Default % | Criteria | +|------|-----------|----------| +| Tier 1 | 0.03% | Simple execution | +| Tier 2 | 0.09% | Optimization/convenience | +| Tier 3 | 0.18% | Risk/urgency — must execute or user loses money | + +Hard costs (`execution_fee` + `cogs`) enforced atomically in UserOp. `value_fee` is post-paid. +Non-execution nodes are free. Both `EstimateFeesResp` and `Execution` use the same `Fee`/`NodeCOGS`/`ValueFee` structure. + +See [docs/FEE_ESTIMATION.md](FEE_ESTIMATION.md) for full details, simulated responses, and billing design. + +## Communication Protocol + +### Aggregator ↔ Operator (gRPC, defined in `protobuf/node.proto`) + +```protobuf +service Node { + rpc Ping(Checkin) returns (CheckinResp); + rpc SyncMessages(SyncMessagesReq) returns (stream SyncMessagesResp); + rpc Ack(AckMessageReq) returns (BoolValue); + rpc NotifyTriggers(NotifyTriggersReq) returns (NotifyTriggersResp); + rpc ReportEventOverload(EventOverloadAlert) returns (EventOverloadResponse); + rpc HealthCheck(HealthCheckRequest) returns (HealthCheckResponse); +} +``` + +Data flow: +1. **Operator → Aggregator**: `Ping` heartbeat every 5s (uptime, queue depth, block number) +2. **Aggregator → Operator**: `SyncMessages` stream pushes task assignments (monitor, disable, delete, immediate trigger) +3. **Operator → Aggregator**: `NotifyTriggers` when conditions met (includes trigger output data + dedup ID) +4. **Operator → Aggregator**: `ReportEventOverload` if event processing exceeds safety limits + +### Client ↔ Aggregator (gRPC, defined in `protobuf/avs.proto`) + +Task management, wallet operations, simulation, fee estimation — all via gRPC on port 2206. + +## Storage + +**Database**: BadgerDB (embedded key-value store) + +Key schema: +``` +t:a: Active task +t:c: Canceled task +t:e: Expired task +history:: Execution record +trigger:: Cached trigger output +q:pending: Pending queue job +q:inprogress: In-progress queue job +user: User info +wallet: Smart wallet mapping +``` + +Data format: Protocol Buffer JSON serialization. Migrations run on startup (idempotent). + +## External Integrations + +| Service | Purpose | Used by | +|---------|---------|---------| +| Moralis API | Token metadata, price feeds | Token enrichment, fee estimation | +| Tenderly | Transaction simulation, gas estimation | Contract write dry-run | +| ERC-4337 Bundler | UserOp submission | On-chain execution | +| EigenLayer contracts | Operator registration, BLS signing | Operator lifecycle | +| SendGrid | Email notifications | REST API node | + +## Configuration + +Environment-specific YAML files in `config/`: +- `aggregator.example.yaml` — Reference config with all fields documented +- `aggregator-sepolia.yaml`, `aggregator-base.yaml`, `aggregator-ethereum.yaml` — Per-chain configs +- `operator-*.yaml` — Operator configs per chain + +Key config sections: smart wallet (RPC, bundler, factory, entrypoint), fee rates (tier-based pricing), macros/secrets (global workflow variables), approved operators list. diff --git a/docs/FEE_ESTIMATION.md b/docs/FEE_ESTIMATION.md new file mode 100644 index 00000000..2b97901a --- /dev/null +++ b/docs/FEE_ESTIMATION.md @@ -0,0 +1,286 @@ +# Fee Estimation + +## Overview + +Workflow fees have three components, each with its own unit: + +| Component | Unit | Purpose | +|-----------|------|---------| +| `execution_fee` | USD | Flat per-run platform fee | +| `cogs[]` | WEI | Per-node operational costs (gas, future: external API) | +| `value_fee` | PERCENTAGE | Workflow-level value capture (% of tx value) | + +Every fee field uses the `Fee{amount, unit}` structure — self-describing, no implicit units. Non-execution nodes (logic, reads, API calls) have **no fees**. + +## Value-Capture Tiers + +Tiers are pure pricing groups — meaning comes from classification logic, not the label. + +### Decision rule + +> If this workflow **fails or is delayed**, does the user **lose money immediately**? +> +> **YES** → Tier 3  |  **NO, but improves outcome** → Tier 2  |  **Simple execution** → Tier 1 + +### Tier definitions + +| Tier | Default % | Classification criteria | Examples | +|------|-----------|----------------------|----------| +| Tier 1 | 0.03% | Simple execution — user could do manually | ETH transfers, simple swaps | +| Tier 2 | 0.09% | Optimization/convenience — delay doesn't cause major loss | Rebalancing, DCA, scheduled swaps | +| Tier 3 | 0.18% | Risk/urgency — must execute or user loses money | Liquidation prevention, auto-repay, stop-loss | + +### V1 vs V2 classification + +- **V1 (current):** Rule-based. All workflows with on-chain nodes default to Tier 1. +- **V2 (future):** LLM-based classification analyzing workflow purpose. e.g., `AAVE.repay()` → Tier 3, `Uniswap.swap()` → Tier 1. + +## What has no fee + +| Node type | Fee | Reason | +|-----------|-----|--------| +| `contract_read` | Free | Read-only, no capital touched | +| `rest_api` | Free (value-capture), but may incur external API COGS | Off-chain call | +| `graphql_query` | Free | Off-chain query | +| `custom_code` | Free | Logic/computation only | +| `branch` | Free | Control flow | +| `filter` | Free | Data filtering | +| `balance` | Free | Read-only check | + +## Operational costs (COGS) + +Gas costs are estimated per on-chain node via `estimateCOGS()`, returned as `NodeCOGS` entries with `Fee{amount, unit: "WEI"}`. Gas estimation is independent of the value-capture tier. + +Default gas estimates: +- `contract_write` — 150,000 gas units +- `eth_transfer` — 50,000 gas units +- `loop` — 300,000 gas units + +Smart wallet creation (if the user's wallet doesn't exist yet) is included as a COGS entry with `cost_type: "wallet_creation"`. + +**External API costs (future):** When a workflow calls a paid external API (e.g., X/Twitter search), that COGS will be estimated and included in the `cogs[]` array. + +## Configuration + +Fee rates are optional. Pointer-based YAML parsing: omitted fields use defaults, explicit `0.0` configures free tiers. + +```yaml +fee_rates: + execution_fee_usd: 0.02 # Flat per-execution platform fee + tiers: + tier_1: 0.03 # Value-capture group 1 + tier_2: 0.09 # Value-capture group 2 + tier_3: 0.18 # Value-capture group 3 +``` + +**Beta (free):** +```yaml +fee_rates: + execution_fee_usd: 0.0 + tiers: + tier_1: 0.0 + tier_2: 0.0 + tier_3: 0.0 +``` + +## Billing & Settlement + +The API returns fees in mixed units — each field is self-describing via `Fee.unit`. + +### Enforcement split + +| Component | Unit | Enforcement | Rationale | +|-----------|------|-------------|-----------| +| `execution_fee` | USD | **Converted to ETH at execution time, included in UserOp** | Reverts if insufficient balance | +| `cogs` (gas, API) | WEI | **Atomic in UserOp** — native token cost | Blockchain rejects if insufficient | +| `value_fee` | PERCENTAGE | **Post-paid** — tracked off-chain after execution | User experiences value first | + +No account balance system or prepaid deposits. The blockchain enforces hard costs — if the smart wallet doesn't have enough ETH, the UserOp reverts automatically. + +### Settlement flow + +``` +1. Build UserOp: + - Include workflow contract calls + - Include execution_fee (converted USD→ETH) + COGS transfer to Ava + +2. Submit to bundler: + - Sufficient balance → executes → fees collected atomically + - Insufficient balance → reverts → nothing happens + +3. After execution, calculate value_fee: + - value_fee_eth = (tier_percentage × tx_value) / eth_price + - Track as outstanding balance (may go negative) + +4. If outstanding value_fee not repaid: + - Block future executions until settled +``` + +## Implementation + +### Key files + +| File | Purpose | +|------|---------| +| `core/taskengine/fee_estimator.go` | `EstimateFees()`, `estimateCOGS()`, `classifyWorkflowValue()`, `buildCOGSFromSteps()` | +| `core/config/config.go` | `FeeRatesConfig` struct, YAML parsing with pointer fields | +| `protobuf/avs.proto` | `Fee`, `NativeToken`, `NodeCOGS`, `ValueFee`, `EstimateFeesResp`, `Execution` | +| `config/aggregator.example.yaml` | Reference YAML with fee config | + +### Fee estimation flow + +``` +EstimateFees(req) + ├─ resolveRunnerAndWalletCreation() → runner address + wallet creation COGS (if needed) + ├─ execution_fee → Fee{amount: "0.02", unit: "USD"} + ├─ estimateCOGS() → NodeCOGS[] with Fee{amount, unit: "WEI"} per on-chain node + ├─ classifyWorkflowValue() → ValueFee{fee: Fee{amount, unit: "PERCENTAGE"}, tier, ...} + └─ response → flat EstimateFeesResp (no totals, client computes) +``` + +### Proto messages + +```protobuf +message Fee { + string amount = 1; // Numeric value as string + string unit = 2; // "USD", "WEI", "PERCENTAGE" +} + +message NativeToken { + string symbol = 1; // e.g., "ETH" + int32 decimals = 2; // e.g., 18 +} + +message NodeCOGS { + string node_id = 1; + string cost_type = 2; // "gas", "external_api", "wallet_creation" + Fee fee = 3; // {amount: "150000000000000", unit: "WEI"} + string gas_units = 4; +} + +message ValueFee { + Fee fee = 1; // {amount: "0.03", unit: "PERCENTAGE"} + ExecutionTier tier = 2; + string value_base = 3; // "input_token_value" + string classification_method = 4; // "rule_based" or "llm" + float confidence = 5; + string reason = 6; +} +``` + +### EstimateFeesResp example responses + +**Workflow 1: Alert-only** (contract_read → branch → rest_api) +```json +{ + "success": true, + "chain_id": "11155111", + "native_token": { "symbol": "ETH", "decimals": 18 }, + "execution_fee": { "amount": "0.020000", "unit": "USD" }, + "cogs": [], + "value_fee": { + "fee": { "amount": "0", "unit": "PERCENTAGE" }, + "tier": "EXECUTION_TIER_UNSPECIFIED", + "value_base": "", + "classification_method": "rule_based", + "confidence": 1.0, + "reason": "Workflow has no on-chain execution nodes — no value-capture fee" + }, + "discounts": [], + "pricing_model": "v1" +} +``` + +**Workflow 2: Simple swap** (contract_read → branch → contract_write) +```json +{ + "success": true, + "chain_id": "11155111", + "native_token": { "symbol": "ETH", "decimals": 18 }, + "execution_fee": { "amount": "0.020000", "unit": "USD" }, + "cogs": [ + { + "node_id": "write1", + "cost_type": "gas", + "fee": { "amount": "2575744500000", "unit": "WEI" }, + "gas_units": "150000" + } + ], + "value_fee": { + "fee": { "amount": "0.03", "unit": "PERCENTAGE" }, + "tier": "EXECUTION_TIER_1", + "value_base": "input_token_value", + "classification_method": "rule_based", + "confidence": 1.0, + "reason": "V1 default: workflow contains on-chain execution nodes" + }, + "discounts": [], + "pricing_model": "v1" +} +``` + +**Workflow 3: Liquidation protection** (contract_read → branch → contract_write → eth_transfer, new wallet) +```json +{ + "success": true, + "chain_id": "11155111", + "native_token": { "symbol": "ETH", "decimals": 18 }, + "execution_fee": { "amount": "0.020000", "unit": "USD" }, + "cogs": [ + { + "node_id": "repay1", + "cost_type": "gas", + "fee": { "amount": "2575744500000", "unit": "WEI" }, + "gas_units": "150000" + }, + { + "node_id": "transfer1", + "cost_type": "gas", + "fee": { "amount": "858581500000", "unit": "WEI" }, + "gas_units": "50000" + }, + { + "node_id": "_wallet_creation", + "cost_type": "wallet_creation", + "fee": { "amount": "6730592094800", "unit": "WEI" } + } + ], + "value_fee": { + "fee": { "amount": "0.03", "unit": "PERCENTAGE" }, + "tier": "EXECUTION_TIER_1", + "value_base": "input_token_value", + "classification_method": "rule_based", + "confidence": 1.0, + "reason": "V1 default: workflow contains on-chain execution nodes" + }, + "discounts": [], + "pricing_model": "v1", + "warnings": ["Gas estimates use conservative fallback values. Actual costs may vary."] +} +``` + +### Execution response (after task runs) + +The `Execution` message uses the same `Fee`/`NodeCOGS`/`ValueFee` structure: + +```protobuf +message Execution { + Fee execution_fee = 7; // Fee{amount: "0.020000", unit: "USD"} + repeated NodeCOGS cogs = 9; // Actual gas from step receipts (via buildCOGSFromSteps) + ValueFee value_fee = 10; // Workflow-level value fee (via buildValueFee) +} +``` + +- `execution_fee` — always populated from config (known upfront) +- `cogs[]` — populated from actual step-level gas receipts after execution (real costs, not estimates) +- `value_fee` — populated after execution based on step composition (nil for pending executions where steps are unknown) +- Step-level gas tracking (`gas_used`, `gas_price`, `total_gas_cost` per step) is preserved as raw execution data + +### Total fee formula + +``` +Total per execution = execution_fee + Σ(cogs) + (value_fee.percentage × tx_value) + |_______atomic (in UserOp)_______| |____post-paid____| +``` + +`execution_fee` and `cogs` are known at estimation time. `value_fee` depends on actual transaction value at execution time. No totals in the API — client computes. diff --git a/protobuf/avs.pb.go b/protobuf/avs.pb.go index 75453d17..3b657ea0 100644 --- a/protobuf/avs.pb.go +++ b/protobuf/avs.pb.go @@ -157,6 +157,61 @@ func (NodeType) EnumDescriptor() ([]byte, []int) { return file_avs_proto_rawDescGZIP(), []int{1} } +// ExecutionTier defines value-capture pricing groups for on-chain execution nodes. +// Tiers are pure pricing buckets — meaning comes from classification logic, not the label. +// Non-execution nodes use UNSPECIFIED (no fee). +type ExecutionTier int32 + +const ( + ExecutionTier_EXECUTION_TIER_UNSPECIFIED ExecutionTier = 0 // No value-capture fee (non-execution nodes) + ExecutionTier_EXECUTION_TIER_1 ExecutionTier = 1 // Pricing group 1 (default: 0.03% of tx value) + ExecutionTier_EXECUTION_TIER_2 ExecutionTier = 2 // Pricing group 2 (default: 0.09% of tx value) + ExecutionTier_EXECUTION_TIER_3 ExecutionTier = 3 // Pricing group 3 (default: 0.18% of tx value) +) + +// Enum value maps for ExecutionTier. +var ( + ExecutionTier_name = map[int32]string{ + 0: "EXECUTION_TIER_UNSPECIFIED", + 1: "EXECUTION_TIER_1", + 2: "EXECUTION_TIER_2", + 3: "EXECUTION_TIER_3", + } + ExecutionTier_value = map[string]int32{ + "EXECUTION_TIER_UNSPECIFIED": 0, + "EXECUTION_TIER_1": 1, + "EXECUTION_TIER_2": 2, + "EXECUTION_TIER_3": 3, + } +) + +func (x ExecutionTier) Enum() *ExecutionTier { + p := new(ExecutionTier) + *p = x + return p +} + +func (x ExecutionTier) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ExecutionTier) Descriptor() protoreflect.EnumDescriptor { + return file_avs_proto_enumTypes[2].Descriptor() +} + +func (ExecutionTier) Type() protoreflect.EnumType { + return &file_avs_proto_enumTypes[2] +} + +func (x ExecutionTier) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ExecutionTier.Descriptor instead. +func (ExecutionTier) EnumDescriptor() ([]byte, []int) { + return file_avs_proto_rawDescGZIP(), []int{2} +} + type ExecutionMode int32 const ( @@ -187,11 +242,11 @@ func (x ExecutionMode) String() string { } func (ExecutionMode) Descriptor() protoreflect.EnumDescriptor { - return file_avs_proto_enumTypes[2].Descriptor() + return file_avs_proto_enumTypes[3].Descriptor() } func (ExecutionMode) Type() protoreflect.EnumType { - return &file_avs_proto_enumTypes[2] + return &file_avs_proto_enumTypes[3] } func (x ExecutionMode) Number() protoreflect.EnumNumber { @@ -200,7 +255,7 @@ func (x ExecutionMode) Number() protoreflect.EnumNumber { // Deprecated: Use ExecutionMode.Descriptor instead. func (ExecutionMode) EnumDescriptor() ([]byte, []int) { - return file_avs_proto_rawDescGZIP(), []int{2} + return file_avs_proto_rawDescGZIP(), []int{3} } // Lang defines supported languages/formats for code editors and data validation @@ -244,11 +299,11 @@ func (x Lang) String() string { } func (Lang) Descriptor() protoreflect.EnumDescriptor { - return file_avs_proto_enumTypes[3].Descriptor() + return file_avs_proto_enumTypes[4].Descriptor() } func (Lang) Type() protoreflect.EnumType { - return &file_avs_proto_enumTypes[3] + return &file_avs_proto_enumTypes[4] } func (x Lang) Number() protoreflect.EnumNumber { @@ -257,7 +312,7 @@ func (x Lang) Number() protoreflect.EnumNumber { // Deprecated: Use Lang.Descriptor instead. func (Lang) EnumDescriptor() ([]byte, []int) { - return file_avs_proto_rawDescGZIP(), []int{3} + return file_avs_proto_rawDescGZIP(), []int{4} } // gRPC internal error code use up to 17, we extend and start from 1000 to avoid any conflict @@ -416,11 +471,11 @@ func (x ErrorCode) String() string { } func (ErrorCode) Descriptor() protoreflect.EnumDescriptor { - return file_avs_proto_enumTypes[4].Descriptor() + return file_avs_proto_enumTypes[5].Descriptor() } func (ErrorCode) Type() protoreflect.EnumType { - return &file_avs_proto_enumTypes[4] + return &file_avs_proto_enumTypes[5] } func (x ErrorCode) Number() protoreflect.EnumNumber { @@ -429,7 +484,7 @@ func (x ErrorCode) Number() protoreflect.EnumNumber { // Deprecated: Use ErrorCode.Descriptor instead. func (ErrorCode) EnumDescriptor() ([]byte, []int) { - return file_avs_proto_rawDescGZIP(), []int{4} + return file_avs_proto_rawDescGZIP(), []int{5} } // TaskStatus represents status of the task. The transition is as follow @@ -473,11 +528,11 @@ func (x TaskStatus) String() string { } func (TaskStatus) Descriptor() protoreflect.EnumDescriptor { - return file_avs_proto_enumTypes[5].Descriptor() + return file_avs_proto_enumTypes[6].Descriptor() } func (TaskStatus) Type() protoreflect.EnumType { - return &file_avs_proto_enumTypes[5] + return &file_avs_proto_enumTypes[6] } func (x TaskStatus) Number() protoreflect.EnumNumber { @@ -486,7 +541,7 @@ func (x TaskStatus) Number() protoreflect.EnumNumber { // Deprecated: Use TaskStatus.Descriptor instead. func (TaskStatus) EnumDescriptor() ([]byte, []int) { - return file_avs_proto_rawDescGZIP(), []int{5} + return file_avs_proto_rawDescGZIP(), []int{6} } // Execution Status re-present a run of the task @@ -529,11 +584,11 @@ func (x ExecutionStatus) String() string { } func (ExecutionStatus) Descriptor() protoreflect.EnumDescriptor { - return file_avs_proto_enumTypes[6].Descriptor() + return file_avs_proto_enumTypes[7].Descriptor() } func (ExecutionStatus) Type() protoreflect.EnumType { - return &file_avs_proto_enumTypes[6] + return &file_avs_proto_enumTypes[7] } func (x ExecutionStatus) Number() protoreflect.EnumNumber { @@ -542,7 +597,7 @@ func (x ExecutionStatus) Number() protoreflect.EnumNumber { // Deprecated: Use ExecutionStatus.Descriptor instead. func (ExecutionStatus) EnumDescriptor() ([]byte, []int) { - return file_avs_proto_rawDescGZIP(), []int{6} + return file_avs_proto_rawDescGZIP(), []int{7} } // TokenMetadata represents ERC20 token information @@ -2038,16 +2093,10 @@ type Execution struct { // index indicates which run this is for the workflow (0-based: 0=1st run, 1=2nd run, etc.) // This helps clients understand execution order without calculating based on timestamps Index int64 `protobuf:"varint,6,opt,name=index,proto3" json:"index,omitempty"` - // Total gas cost for the entire workflow execution (sum of all blockchain operations) - // Units are in wei. Use string for large numbers to avoid overflow. - // - // Empty string means gas data was not computed (e.g., workflow has no on-chain steps, - // or receipt was unavailable). Clients should treat both "" and "0" as "no data" - // since real on-chain transactions always cost gas. - TotalGasCost string `protobuf:"bytes,7,opt,name=total_gas_cost,json=totalGasCost,proto3" json:"total_gas_cost,omitempty"` - // Automation fee charged for monitoring and executing this workflow. - // Currently hard-coded to zero; will be populated when automation fees are enabled. - AutomationFee *FeeAmount `protobuf:"bytes,9,opt,name=automation_fee,json=automationFee,proto3" json:"automation_fee,omitempty"` + // Fees actually charged for this execution (matches EstimateFeesResp format) + ExecutionFee *Fee `protobuf:"bytes,7,opt,name=execution_fee,json=executionFee,proto3" json:"execution_fee,omitempty"` // Flat platform fee charged {amount, unit: "USD"} + Cogs []*NodeCOGS `protobuf:"bytes,9,rep,name=cogs,proto3" json:"cogs,omitempty"` // Per-node actual gas/API costs {fee: {amount, unit: "WEI"}} + ValueFee *ValueFee `protobuf:"bytes,10,opt,name=value_fee,json=valueFee,proto3" json:"value_fee,omitempty"` // Value-capture fee charged (post-paid) {fee: {amount, unit: "PERCENTAGE"}} Steps []*Execution_Step `protobuf:"bytes,8,rep,name=steps,proto3" json:"steps,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -2125,16 +2174,23 @@ func (x *Execution) GetIndex() int64 { return 0 } -func (x *Execution) GetTotalGasCost() string { +func (x *Execution) GetExecutionFee() *Fee { if x != nil { - return x.TotalGasCost + return x.ExecutionFee } - return "" + return nil +} + +func (x *Execution) GetCogs() []*NodeCOGS { + if x != nil { + return x.Cogs + } + return nil } -func (x *Execution) GetAutomationFee() *FeeAmount { +func (x *Execution) GetValueFee() *ValueFee { if x != nil { - return x.AutomationFee + return x.ValueFee } return nil } @@ -6233,35 +6289,30 @@ func (x *SmartWalletCreationFee) GetWalletAddress() string { return "" } -// Automation fee structure based on trigger type and duration -type AutomationFee struct { +// Unit-safe fee value. Every monetary field is self-describing. +// Units: "USD" (fiat), "WEI" (native token smallest unit), "PERCENTAGE" (0.03 = 0.03%) +type Fee struct { state protoimpl.MessageState `protogen:"open.v1"` - BaseFee *FeeAmount `protobuf:"bytes,1,opt,name=base_fee,json=baseFee,proto3" json:"base_fee,omitempty"` // Base automation fee - MonitoringFee *FeeAmount `protobuf:"bytes,2,opt,name=monitoring_fee,json=monitoringFee,proto3" json:"monitoring_fee,omitempty"` // Ongoing monitoring cost (for time/event triggers) - ExecutionFee *FeeAmount `protobuf:"bytes,3,opt,name=execution_fee,json=executionFee,proto3" json:"execution_fee,omitempty"` // Per-execution fee - // Fee calculation details - TriggerType string `protobuf:"bytes,4,opt,name=trigger_type,json=triggerType,proto3" json:"trigger_type,omitempty"` // "manual", "cron", "event", "block", "fixed_time" - EstimatedExecutions int64 `protobuf:"varint,5,opt,name=estimated_executions,json=estimatedExecutions,proto3" json:"estimated_executions,omitempty"` // Estimated number of executions over workflow lifetime - DurationMinutes int64 `protobuf:"varint,6,opt,name=duration_minutes,json=durationMinutes,proto3" json:"duration_minutes,omitempty"` // How long monitoring will run (minutes) - FeeCalculationMethod string `protobuf:"bytes,7,opt,name=fee_calculation_method,json=feeCalculationMethod,proto3" json:"fee_calculation_method,omitempty"` // Description of how fee was calculated - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` // Numeric value as string (precision-safe) + Unit string `protobuf:"bytes,2,opt,name=unit,proto3" json:"unit,omitempty"` // "USD", "WEI", "PERCENTAGE" + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *AutomationFee) Reset() { - *x = AutomationFee{} +func (x *Fee) Reset() { + *x = Fee{} mi := &file_avs_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *AutomationFee) String() string { +func (x *Fee) String() string { return protoimpl.X.MessageStringOf(x) } -func (*AutomationFee) ProtoMessage() {} +func (*Fee) ProtoMessage() {} -func (x *AutomationFee) ProtoReflect() protoreflect.Message { +func (x *Fee) ProtoReflect() protoreflect.Message { mi := &file_avs_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -6273,77 +6324,248 @@ func (x *AutomationFee) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use AutomationFee.ProtoReflect.Descriptor instead. -func (*AutomationFee) Descriptor() ([]byte, []int) { +// Deprecated: Use Fee.ProtoReflect.Descriptor instead. +func (*Fee) Descriptor() ([]byte, []int) { return file_avs_proto_rawDescGZIP(), []int{76} } -func (x *AutomationFee) GetBaseFee() *FeeAmount { +func (x *Fee) GetAmount() string { if x != nil { - return x.BaseFee + return x.Amount } - return nil + return "" +} + +func (x *Fee) GetUnit() string { + if x != nil { + return x.Unit + } + return "" +} + +// Native token metadata for the chain +type NativeToken struct { + state protoimpl.MessageState `protogen:"open.v1"` + Symbol string `protobuf:"bytes,1,opt,name=symbol,proto3" json:"symbol,omitempty"` // e.g., "ETH" + Decimals int32 `protobuf:"varint,2,opt,name=decimals,proto3" json:"decimals,omitempty"` // e.g., 18 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NativeToken) Reset() { + *x = NativeToken{} + mi := &file_avs_proto_msgTypes[77] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NativeToken) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NativeToken) ProtoMessage() {} + +func (x *NativeToken) ProtoReflect() protoreflect.Message { + mi := &file_avs_proto_msgTypes[77] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NativeToken.ProtoReflect.Descriptor instead. +func (*NativeToken) Descriptor() ([]byte, []int) { + return file_avs_proto_rawDescGZIP(), []int{77} +} + +func (x *NativeToken) GetSymbol() string { + if x != nil { + return x.Symbol + } + return "" +} + +func (x *NativeToken) GetDecimals() int32 { + if x != nil { + return x.Decimals + } + return 0 +} + +// Per-node cost of goods sold (gas, external API costs, etc.) +type NodeCOGS struct { + state protoimpl.MessageState `protogen:"open.v1"` + NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + CostType string `protobuf:"bytes,2,opt,name=cost_type,json=costType,proto3" json:"cost_type,omitempty"` // "gas", "external_api", "wallet_creation" + Fee *Fee `protobuf:"bytes,3,opt,name=fee,proto3" json:"fee,omitempty"` // Cost in WEI + GasUnits string `protobuf:"bytes,4,opt,name=gas_units,json=gasUnits,proto3" json:"gas_units,omitempty"` // Gas units (for gas costs only) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NodeCOGS) Reset() { + *x = NodeCOGS{} + mi := &file_avs_proto_msgTypes[78] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NodeCOGS) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeCOGS) ProtoMessage() {} + +func (x *NodeCOGS) ProtoReflect() protoreflect.Message { + mi := &file_avs_proto_msgTypes[78] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -func (x *AutomationFee) GetMonitoringFee() *FeeAmount { +// Deprecated: Use NodeCOGS.ProtoReflect.Descriptor instead. +func (*NodeCOGS) Descriptor() ([]byte, []int) { + return file_avs_proto_rawDescGZIP(), []int{78} +} + +func (x *NodeCOGS) GetNodeId() string { if x != nil { - return x.MonitoringFee + return x.NodeId + } + return "" +} + +func (x *NodeCOGS) GetCostType() string { + if x != nil { + return x.CostType + } + return "" +} + +func (x *NodeCOGS) GetFee() *Fee { + if x != nil { + return x.Fee } return nil } -func (x *AutomationFee) GetExecutionFee() *FeeAmount { +func (x *NodeCOGS) GetGasUnits() string { if x != nil { - return x.ExecutionFee + return x.GasUnits + } + return "" +} + +// Workflow-level value-capture fee. +// Single fee for the entire workflow based on what it does (not per-node). +type ValueFee struct { + state protoimpl.MessageState `protogen:"open.v1"` + Fee *Fee `protobuf:"bytes,1,opt,name=fee,proto3" json:"fee,omitempty"` // { amount: "0.03", unit: "PERCENTAGE" } + Tier ExecutionTier `protobuf:"varint,2,opt,name=tier,proto3,enum=aggregator.ExecutionTier" json:"tier,omitempty"` // Pricing group (TIER_1, TIER_2, TIER_3) + ValueBase string `protobuf:"bytes,3,opt,name=value_base,json=valueBase,proto3" json:"value_base,omitempty"` // What the percentage applies to (e.g., "input_token_value") + ClassificationMethod string `protobuf:"bytes,4,opt,name=classification_method,json=classificationMethod,proto3" json:"classification_method,omitempty"` // "rule_based" (V1) or "llm" (V2) + Confidence float32 `protobuf:"fixed32,5,opt,name=confidence,proto3" json:"confidence,omitempty"` // Classification confidence (0.0–1.0) + Reason string `protobuf:"bytes,6,opt,name=reason,proto3" json:"reason,omitempty"` // Why this tier was assigned + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ValueFee) Reset() { + *x = ValueFee{} + mi := &file_avs_proto_msgTypes[79] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ValueFee) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValueFee) ProtoMessage() {} + +func (x *ValueFee) ProtoReflect() protoreflect.Message { + mi := &file_avs_proto_msgTypes[79] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValueFee.ProtoReflect.Descriptor instead. +func (*ValueFee) Descriptor() ([]byte, []int) { + return file_avs_proto_rawDescGZIP(), []int{79} +} + +func (x *ValueFee) GetFee() *Fee { + if x != nil { + return x.Fee } return nil } -func (x *AutomationFee) GetTriggerType() string { +func (x *ValueFee) GetTier() ExecutionTier { if x != nil { - return x.TriggerType + return x.Tier + } + return ExecutionTier_EXECUTION_TIER_UNSPECIFIED +} + +func (x *ValueFee) GetValueBase() string { + if x != nil { + return x.ValueBase } return "" } -func (x *AutomationFee) GetEstimatedExecutions() int64 { +func (x *ValueFee) GetClassificationMethod() string { if x != nil { - return x.EstimatedExecutions + return x.ClassificationMethod } - return 0 + return "" } -func (x *AutomationFee) GetDurationMinutes() int64 { +func (x *ValueFee) GetConfidence() float32 { if x != nil { - return x.DurationMinutes + return x.Confidence } return 0 } -func (x *AutomationFee) GetFeeCalculationMethod() string { +func (x *ValueFee) GetReason() string { if x != nil { - return x.FeeCalculationMethod + return x.Reason } return "" } -// Promotional discounts and fee reductions +// Promotional discount type FeeDiscount struct { - state protoimpl.MessageState `protogen:"open.v1"` - DiscountType string `protobuf:"bytes,1,opt,name=discount_type,json=discountType,proto3" json:"discount_type,omitempty"` // "new_user", "volume", "promotional", "beta_program" - DiscountName string `protobuf:"bytes,2,opt,name=discount_name,json=discountName,proto3" json:"discount_name,omitempty"` // Human-readable discount name - AppliesTo string `protobuf:"bytes,3,opt,name=applies_to,json=appliesTo,proto3" json:"applies_to,omitempty"` // "gas_fees", "automation_fees", "creation_fees", "all" - DiscountPercentage float32 `protobuf:"fixed32,4,opt,name=discount_percentage,json=discountPercentage,proto3" json:"discount_percentage,omitempty"` // Discount percentage (0.0 to 100.0) - DiscountAmount *FeeAmount `protobuf:"bytes,5,opt,name=discount_amount,json=discountAmount,proto3" json:"discount_amount,omitempty"` // Absolute discount amount - ExpiryDate string `protobuf:"bytes,6,opt,name=expiry_date,json=expiryDate,proto3" json:"expiry_date,omitempty"` // When discount expires (ISO 8601 format) - Terms string `protobuf:"bytes,7,opt,name=terms,proto3" json:"terms,omitempty"` // Terms and conditions for discount - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + DiscountType string `protobuf:"bytes,1,opt,name=discount_type,json=discountType,proto3" json:"discount_type,omitempty"` // "new_user", "volume", "promotional", "beta_program" + DiscountName string `protobuf:"bytes,2,opt,name=discount_name,json=discountName,proto3" json:"discount_name,omitempty"` + Discount *Fee `protobuf:"bytes,3,opt,name=discount,proto3" json:"discount,omitempty"` // Discount amount or percentage + ExpiryDate string `protobuf:"bytes,4,opt,name=expiry_date,json=expiryDate,proto3" json:"expiry_date,omitempty"` + Terms string `protobuf:"bytes,5,opt,name=terms,proto3" json:"terms,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *FeeDiscount) Reset() { *x = FeeDiscount{} - mi := &file_avs_proto_msgTypes[77] + mi := &file_avs_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6355,7 +6577,7 @@ func (x *FeeDiscount) String() string { func (*FeeDiscount) ProtoMessage() {} func (x *FeeDiscount) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[77] + mi := &file_avs_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6368,7 +6590,7 @@ func (x *FeeDiscount) ProtoReflect() protoreflect.Message { // Deprecated: Use FeeDiscount.ProtoReflect.Descriptor instead. func (*FeeDiscount) Descriptor() ([]byte, []int) { - return file_avs_proto_rawDescGZIP(), []int{77} + return file_avs_proto_rawDescGZIP(), []int{80} } func (x *FeeDiscount) GetDiscountType() string { @@ -6385,23 +6607,9 @@ func (x *FeeDiscount) GetDiscountName() string { return "" } -func (x *FeeDiscount) GetAppliesTo() string { - if x != nil { - return x.AppliesTo - } - return "" -} - -func (x *FeeDiscount) GetDiscountPercentage() float32 { - if x != nil { - return x.DiscountPercentage - } - return 0 -} - -func (x *FeeDiscount) GetDiscountAmount() *FeeAmount { +func (x *FeeDiscount) GetDiscount() *Fee { if x != nil { - return x.DiscountAmount + return x.Discount } return nil } @@ -6421,36 +6629,34 @@ func (x *FeeDiscount) GetTerms() string { } // Response message for EstimateFees +// All fees are per-execution. No totals — client computes. +// Components: execution_fee (USD) + cogs[] (WEI) + value_fee (PERCENTAGE) type EstimateFeesResp struct { state protoimpl.MessageState `protogen:"open.v1"` - Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` // Whether fee estimation was successful - Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` // Error message if estimation failed - ErrorCode ErrorCode `protobuf:"varint,3,opt,name=error_code,json=errorCode,proto3,enum=aggregator.ErrorCode" json:"error_code,omitempty"` // Structured error code - // Fee breakdown - GasFees *GasFeeBreakdown `protobuf:"bytes,4,opt,name=gas_fees,json=gasFees,proto3" json:"gas_fees,omitempty"` // Estimated gas fees - AutomationFees *AutomationFee `protobuf:"bytes,5,opt,name=automation_fees,json=automationFees,proto3" json:"automation_fees,omitempty"` // Automation and monitoring fees - CreationFees *SmartWalletCreationFee `protobuf:"bytes,6,opt,name=creation_fees,json=creationFees,proto3" json:"creation_fees,omitempty"` // Smart wallet creation fees (if needed) - // Total fees - TotalFees *FeeAmount `protobuf:"bytes,7,opt,name=total_fees,json=totalFees,proto3" json:"total_fees,omitempty"` // Sum of all fees - // Discounts and promotions - Discounts []*FeeDiscount `protobuf:"bytes,8,rep,name=discounts,proto3" json:"discounts,omitempty"` // Applied discounts - TotalDiscounts *FeeAmount `protobuf:"bytes,9,opt,name=total_discounts,json=totalDiscounts,proto3" json:"total_discounts,omitempty"` // Total discount amount - FinalTotal *FeeAmount `protobuf:"bytes,10,opt,name=final_total,json=finalTotal,proto3" json:"final_total,omitempty"` // Final total after discounts - // Estimation metadata - EstimatedAt int64 `protobuf:"varint,11,opt,name=estimated_at,json=estimatedAt,proto3" json:"estimated_at,omitempty"` // Timestamp when estimation was performed - ChainId string `protobuf:"bytes,12,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` // Blockchain chain ID - PriceDataSource string `protobuf:"bytes,13,opt,name=price_data_source,json=priceDataSource,proto3" json:"price_data_source,omitempty"` // Source of price data ("coingecko", "chainlink", "cached") - PriceDataAgeSeconds int64 `protobuf:"varint,14,opt,name=price_data_age_seconds,json=priceDataAgeSeconds,proto3" json:"price_data_age_seconds,omitempty"` // Age of price data in seconds - // Warnings and recommendations - Warnings []string `protobuf:"bytes,15,rep,name=warnings,proto3" json:"warnings,omitempty"` // Warnings about fee estimation - Recommendations []string `protobuf:"bytes,16,rep,name=recommendations,proto3" json:"recommendations,omitempty"` // Recommendations for cost optimization - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` + ErrorCode ErrorCode `protobuf:"varint,3,opt,name=error_code,json=errorCode,proto3,enum=aggregator.ErrorCode" json:"error_code,omitempty"` + // Chain and token context + ChainId string `protobuf:"bytes,4,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + NativeToken *NativeToken `protobuf:"bytes,5,opt,name=native_token,json=nativeToken,proto3" json:"native_token,omitempty"` + // Flat per-execution platform fee + ExecutionFee *Fee `protobuf:"bytes,6,opt,name=execution_fee,json=executionFee,proto3" json:"execution_fee,omitempty"` + // Cost of goods sold — per-node operational costs (gas, external API) + Cogs []*NodeCOGS `protobuf:"bytes,7,rep,name=cogs,proto3" json:"cogs,omitempty"` + // Workflow-level value-capture fee (single, not per-node) + ValueFee *ValueFee `protobuf:"bytes,8,opt,name=value_fee,json=valueFee,proto3" json:"value_fee,omitempty"` + // Discounts (client sums if needed) + Discounts []*FeeDiscount `protobuf:"bytes,9,rep,name=discounts,proto3" json:"discounts,omitempty"` + // Pricing metadata + PricingModel string `protobuf:"bytes,10,opt,name=pricing_model,json=pricingModel,proto3" json:"pricing_model,omitempty"` // "v1" + Warnings []string `protobuf:"bytes,11,rep,name=warnings,proto3" json:"warnings,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *EstimateFeesResp) Reset() { *x = EstimateFeesResp{} - mi := &file_avs_proto_msgTypes[78] + mi := &file_avs_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6462,7 +6668,7 @@ func (x *EstimateFeesResp) String() string { func (*EstimateFeesResp) ProtoMessage() {} func (x *EstimateFeesResp) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[78] + mi := &file_avs_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6475,7 +6681,7 @@ func (x *EstimateFeesResp) ProtoReflect() protoreflect.Message { // Deprecated: Use EstimateFeesResp.ProtoReflect.Descriptor instead. func (*EstimateFeesResp) Descriptor() ([]byte, []int) { - return file_avs_proto_rawDescGZIP(), []int{78} + return file_avs_proto_rawDescGZIP(), []int{81} } func (x *EstimateFeesResp) GetSuccess() bool { @@ -6499,83 +6705,55 @@ func (x *EstimateFeesResp) GetErrorCode() ErrorCode { return ErrorCode_ERROR_CODE_UNSPECIFIED } -func (x *EstimateFeesResp) GetGasFees() *GasFeeBreakdown { - if x != nil { - return x.GasFees - } - return nil -} - -func (x *EstimateFeesResp) GetAutomationFees() *AutomationFee { +func (x *EstimateFeesResp) GetChainId() string { if x != nil { - return x.AutomationFees + return x.ChainId } - return nil + return "" } -func (x *EstimateFeesResp) GetCreationFees() *SmartWalletCreationFee { +func (x *EstimateFeesResp) GetNativeToken() *NativeToken { if x != nil { - return x.CreationFees + return x.NativeToken } return nil } -func (x *EstimateFeesResp) GetTotalFees() *FeeAmount { +func (x *EstimateFeesResp) GetExecutionFee() *Fee { if x != nil { - return x.TotalFees + return x.ExecutionFee } return nil } -func (x *EstimateFeesResp) GetDiscounts() []*FeeDiscount { +func (x *EstimateFeesResp) GetCogs() []*NodeCOGS { if x != nil { - return x.Discounts + return x.Cogs } return nil } -func (x *EstimateFeesResp) GetTotalDiscounts() *FeeAmount { +func (x *EstimateFeesResp) GetValueFee() *ValueFee { if x != nil { - return x.TotalDiscounts + return x.ValueFee } return nil } -func (x *EstimateFeesResp) GetFinalTotal() *FeeAmount { +func (x *EstimateFeesResp) GetDiscounts() []*FeeDiscount { if x != nil { - return x.FinalTotal + return x.Discounts } return nil } -func (x *EstimateFeesResp) GetEstimatedAt() int64 { - if x != nil { - return x.EstimatedAt - } - return 0 -} - -func (x *EstimateFeesResp) GetChainId() string { +func (x *EstimateFeesResp) GetPricingModel() string { if x != nil { - return x.ChainId + return x.PricingModel } return "" } -func (x *EstimateFeesResp) GetPriceDataSource() string { - if x != nil { - return x.PriceDataSource - } - return "" -} - -func (x *EstimateFeesResp) GetPriceDataAgeSeconds() int64 { - if x != nil { - return x.PriceDataAgeSeconds - } - return 0 -} - func (x *EstimateFeesResp) GetWarnings() []string { if x != nil { return x.Warnings @@ -6583,13 +6761,6 @@ func (x *EstimateFeesResp) GetWarnings() []string { return nil } -func (x *EstimateFeesResp) GetRecommendations() []string { - if x != nil { - return x.Recommendations - } - return nil -} - // EventCondition represents a condition to evaluate on decoded event data type EventCondition struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -6603,7 +6774,7 @@ type EventCondition struct { func (x *EventCondition) Reset() { *x = EventCondition{} - mi := &file_avs_proto_msgTypes[79] + mi := &file_avs_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6615,7 +6786,7 @@ func (x *EventCondition) String() string { func (*EventCondition) ProtoMessage() {} func (x *EventCondition) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[79] + mi := &file_avs_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6628,7 +6799,7 @@ func (x *EventCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use EventCondition.ProtoReflect.Descriptor instead. func (*EventCondition) Descriptor() ([]byte, []int) { - return file_avs_proto_rawDescGZIP(), []int{79} + return file_avs_proto_rawDescGZIP(), []int{82} } func (x *EventCondition) GetFieldName() string { @@ -6668,7 +6839,7 @@ type FixedTimeTrigger_Config struct { func (x *FixedTimeTrigger_Config) Reset() { *x = FixedTimeTrigger_Config{} - mi := &file_avs_proto_msgTypes[80] + mi := &file_avs_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6680,7 +6851,7 @@ func (x *FixedTimeTrigger_Config) String() string { func (*FixedTimeTrigger_Config) ProtoMessage() {} func (x *FixedTimeTrigger_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[80] + mi := &file_avs_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6712,7 +6883,7 @@ type FixedTimeTrigger_Output struct { func (x *FixedTimeTrigger_Output) Reset() { *x = FixedTimeTrigger_Output{} - mi := &file_avs_proto_msgTypes[81] + mi := &file_avs_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6724,7 +6895,7 @@ func (x *FixedTimeTrigger_Output) String() string { func (*FixedTimeTrigger_Output) ProtoMessage() {} func (x *FixedTimeTrigger_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[81] + mi := &file_avs_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6756,7 +6927,7 @@ type CronTrigger_Config struct { func (x *CronTrigger_Config) Reset() { *x = CronTrigger_Config{} - mi := &file_avs_proto_msgTypes[82] + mi := &file_avs_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6768,7 +6939,7 @@ func (x *CronTrigger_Config) String() string { func (*CronTrigger_Config) ProtoMessage() {} func (x *CronTrigger_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[82] + mi := &file_avs_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6800,7 +6971,7 @@ type CronTrigger_Output struct { func (x *CronTrigger_Output) Reset() { *x = CronTrigger_Output{} - mi := &file_avs_proto_msgTypes[83] + mi := &file_avs_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6812,7 +6983,7 @@ func (x *CronTrigger_Output) String() string { func (*CronTrigger_Output) ProtoMessage() {} func (x *CronTrigger_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[83] + mi := &file_avs_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6844,7 +7015,7 @@ type BlockTrigger_Config struct { func (x *BlockTrigger_Config) Reset() { *x = BlockTrigger_Config{} - mi := &file_avs_proto_msgTypes[84] + mi := &file_avs_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6856,7 +7027,7 @@ func (x *BlockTrigger_Config) String() string { func (*BlockTrigger_Config) ProtoMessage() {} func (x *BlockTrigger_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[84] + mi := &file_avs_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6888,7 +7059,7 @@ type BlockTrigger_Output struct { func (x *BlockTrigger_Output) Reset() { *x = BlockTrigger_Output{} - mi := &file_avs_proto_msgTypes[85] + mi := &file_avs_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6900,7 +7071,7 @@ func (x *BlockTrigger_Output) String() string { func (*BlockTrigger_Output) ProtoMessage() {} func (x *BlockTrigger_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[85] + mi := &file_avs_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6960,7 +7131,7 @@ type EventTrigger_Query struct { func (x *EventTrigger_Query) Reset() { *x = EventTrigger_Query{} - mi := &file_avs_proto_msgTypes[86] + mi := &file_avs_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6972,7 +7143,7 @@ func (x *EventTrigger_Query) String() string { func (*EventTrigger_Query) ProtoMessage() {} func (x *EventTrigger_Query) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[86] + mi := &file_avs_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7043,7 +7214,7 @@ type EventTrigger_MethodCall struct { func (x *EventTrigger_MethodCall) Reset() { *x = EventTrigger_MethodCall{} - mi := &file_avs_proto_msgTypes[87] + mi := &file_avs_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7055,7 +7226,7 @@ func (x *EventTrigger_MethodCall) String() string { func (*EventTrigger_MethodCall) ProtoMessage() {} func (x *EventTrigger_MethodCall) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[87] + mi := &file_avs_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7116,7 +7287,7 @@ type EventTrigger_Config struct { func (x *EventTrigger_Config) Reset() { *x = EventTrigger_Config{} - mi := &file_avs_proto_msgTypes[88] + mi := &file_avs_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7128,7 +7299,7 @@ func (x *EventTrigger_Config) String() string { func (*EventTrigger_Config) ProtoMessage() {} func (x *EventTrigger_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[88] + mi := &file_avs_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7167,7 +7338,7 @@ type EventTrigger_Output struct { func (x *EventTrigger_Output) Reset() { *x = EventTrigger_Output{} - mi := &file_avs_proto_msgTypes[89] + mi := &file_avs_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7179,7 +7350,7 @@ func (x *EventTrigger_Output) String() string { func (*EventTrigger_Output) ProtoMessage() {} func (x *EventTrigger_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[89] + mi := &file_avs_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7219,7 +7390,7 @@ type ManualTrigger_Config struct { func (x *ManualTrigger_Config) Reset() { *x = ManualTrigger_Config{} - mi := &file_avs_proto_msgTypes[90] + mi := &file_avs_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7231,7 +7402,7 @@ func (x *ManualTrigger_Config) String() string { func (*ManualTrigger_Config) ProtoMessage() {} func (x *ManualTrigger_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[90] + mi := &file_avs_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7285,7 +7456,7 @@ type ManualTrigger_Output struct { func (x *ManualTrigger_Output) Reset() { *x = ManualTrigger_Output{} - mi := &file_avs_proto_msgTypes[91] + mi := &file_avs_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7297,7 +7468,7 @@ func (x *ManualTrigger_Output) String() string { func (*ManualTrigger_Output) ProtoMessage() {} func (x *ManualTrigger_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[91] + mi := &file_avs_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7330,7 +7501,7 @@ type ETHTransferNode_Config struct { func (x *ETHTransferNode_Config) Reset() { *x = ETHTransferNode_Config{} - mi := &file_avs_proto_msgTypes[94] + mi := &file_avs_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7342,7 +7513,7 @@ func (x *ETHTransferNode_Config) String() string { func (*ETHTransferNode_Config) ProtoMessage() {} func (x *ETHTransferNode_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[94] + mi := &file_avs_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7381,7 +7552,7 @@ type ETHTransferNode_Output struct { func (x *ETHTransferNode_Output) Reset() { *x = ETHTransferNode_Output{} - mi := &file_avs_proto_msgTypes[95] + mi := &file_avs_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7393,7 +7564,7 @@ func (x *ETHTransferNode_Output) String() string { func (*ETHTransferNode_Output) ProtoMessage() {} func (x *ETHTransferNode_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[95] + mi := &file_avs_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7436,7 +7607,7 @@ type ContractWriteNode_Config struct { func (x *ContractWriteNode_Config) Reset() { *x = ContractWriteNode_Config{} - mi := &file_avs_proto_msgTypes[96] + mi := &file_avs_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7448,7 +7619,7 @@ func (x *ContractWriteNode_Config) String() string { func (*ContractWriteNode_Config) ProtoMessage() {} func (x *ContractWriteNode_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[96] + mi := &file_avs_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7525,7 +7696,7 @@ type ContractWriteNode_MethodCall struct { func (x *ContractWriteNode_MethodCall) Reset() { *x = ContractWriteNode_MethodCall{} - mi := &file_avs_proto_msgTypes[97] + mi := &file_avs_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7537,7 +7708,7 @@ func (x *ContractWriteNode_MethodCall) String() string { func (*ContractWriteNode_MethodCall) ProtoMessage() {} func (x *ContractWriteNode_MethodCall) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[97] + mi := &file_avs_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7592,7 +7763,7 @@ type ContractWriteNode_Output struct { func (x *ContractWriteNode_Output) Reset() { *x = ContractWriteNode_Output{} - mi := &file_avs_proto_msgTypes[98] + mi := &file_avs_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7604,7 +7775,7 @@ func (x *ContractWriteNode_Output) String() string { func (*ContractWriteNode_Output) ProtoMessage() {} func (x *ContractWriteNode_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[98] + mi := &file_avs_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7642,7 +7813,7 @@ type ContractWriteNode_MethodResult struct { func (x *ContractWriteNode_MethodResult) Reset() { *x = ContractWriteNode_MethodResult{} - mi := &file_avs_proto_msgTypes[99] + mi := &file_avs_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7654,7 +7825,7 @@ func (x *ContractWriteNode_MethodResult) String() string { func (*ContractWriteNode_MethodResult) ProtoMessage() {} func (x *ContractWriteNode_MethodResult) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[99] + mi := &file_avs_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7731,7 +7902,7 @@ type ContractReadNode_MethodCall struct { func (x *ContractReadNode_MethodCall) Reset() { *x = ContractReadNode_MethodCall{} - mi := &file_avs_proto_msgTypes[100] + mi := &file_avs_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7743,7 +7914,7 @@ func (x *ContractReadNode_MethodCall) String() string { func (*ContractReadNode_MethodCall) ProtoMessage() {} func (x *ContractReadNode_MethodCall) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[100] + mi := &file_avs_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7800,7 +7971,7 @@ type ContractReadNode_Config struct { func (x *ContractReadNode_Config) Reset() { *x = ContractReadNode_Config{} - mi := &file_avs_proto_msgTypes[101] + mi := &file_avs_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7812,7 +7983,7 @@ func (x *ContractReadNode_Config) String() string { func (*ContractReadNode_Config) ProtoMessage() {} func (x *ContractReadNode_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[101] + mi := &file_avs_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7862,7 +8033,7 @@ type ContractReadNode_MethodResult struct { func (x *ContractReadNode_MethodResult) Reset() { *x = ContractReadNode_MethodResult{} - mi := &file_avs_proto_msgTypes[102] + mi := &file_avs_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7874,7 +8045,7 @@ func (x *ContractReadNode_MethodResult) String() string { func (*ContractReadNode_MethodResult) ProtoMessage() {} func (x *ContractReadNode_MethodResult) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[102] + mi := &file_avs_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7929,7 +8100,7 @@ type ContractReadNode_Output struct { func (x *ContractReadNode_Output) Reset() { *x = ContractReadNode_Output{} - mi := &file_avs_proto_msgTypes[103] + mi := &file_avs_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7941,7 +8112,7 @@ func (x *ContractReadNode_Output) String() string { func (*ContractReadNode_Output) ProtoMessage() {} func (x *ContractReadNode_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[103] + mi := &file_avs_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7976,7 +8147,7 @@ type ContractReadNode_MethodResult_StructuredField struct { func (x *ContractReadNode_MethodResult_StructuredField) Reset() { *x = ContractReadNode_MethodResult_StructuredField{} - mi := &file_avs_proto_msgTypes[104] + mi := &file_avs_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7988,7 +8159,7 @@ func (x *ContractReadNode_MethodResult_StructuredField) String() string { func (*ContractReadNode_MethodResult_StructuredField) ProtoMessage() {} func (x *ContractReadNode_MethodResult_StructuredField) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[104] + mi := &file_avs_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8037,7 +8208,7 @@ type GraphQLQueryNode_Config struct { func (x *GraphQLQueryNode_Config) Reset() { *x = GraphQLQueryNode_Config{} - mi := &file_avs_proto_msgTypes[105] + mi := &file_avs_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8049,7 +8220,7 @@ func (x *GraphQLQueryNode_Config) String() string { func (*GraphQLQueryNode_Config) ProtoMessage() {} func (x *GraphQLQueryNode_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[105] + mi := &file_avs_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8097,7 +8268,7 @@ type GraphQLQueryNode_Output struct { func (x *GraphQLQueryNode_Output) Reset() { *x = GraphQLQueryNode_Output{} - mi := &file_avs_proto_msgTypes[106] + mi := &file_avs_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8109,7 +8280,7 @@ func (x *GraphQLQueryNode_Output) String() string { func (*GraphQLQueryNode_Output) ProtoMessage() {} func (x *GraphQLQueryNode_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[106] + mi := &file_avs_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8146,7 +8317,7 @@ type RestAPINode_Config struct { func (x *RestAPINode_Config) Reset() { *x = RestAPINode_Config{} - mi := &file_avs_proto_msgTypes[108] + mi := &file_avs_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8158,7 +8329,7 @@ func (x *RestAPINode_Config) String() string { func (*RestAPINode_Config) ProtoMessage() {} func (x *RestAPINode_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[108] + mi := &file_avs_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8219,7 +8390,7 @@ type RestAPINode_Output struct { func (x *RestAPINode_Output) Reset() { *x = RestAPINode_Output{} - mi := &file_avs_proto_msgTypes[109] + mi := &file_avs_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8231,7 +8402,7 @@ func (x *RestAPINode_Output) String() string { func (*RestAPINode_Output) ProtoMessage() {} func (x *RestAPINode_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[109] + mi := &file_avs_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8264,7 +8435,7 @@ type CustomCodeNode_Config struct { func (x *CustomCodeNode_Config) Reset() { *x = CustomCodeNode_Config{} - mi := &file_avs_proto_msgTypes[111] + mi := &file_avs_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8276,7 +8447,7 @@ func (x *CustomCodeNode_Config) String() string { func (*CustomCodeNode_Config) ProtoMessage() {} func (x *CustomCodeNode_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[111] + mi := &file_avs_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8316,7 +8487,7 @@ type CustomCodeNode_Output struct { func (x *CustomCodeNode_Output) Reset() { *x = CustomCodeNode_Output{} - mi := &file_avs_proto_msgTypes[112] + mi := &file_avs_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8328,7 +8499,7 @@ func (x *CustomCodeNode_Output) String() string { func (*CustomCodeNode_Output) ProtoMessage() {} func (x *CustomCodeNode_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[112] + mi := &file_avs_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8393,7 +8564,7 @@ type BalanceNode_Config struct { func (x *BalanceNode_Config) Reset() { *x = BalanceNode_Config{} - mi := &file_avs_proto_msgTypes[113] + mi := &file_avs_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8405,7 +8576,7 @@ func (x *BalanceNode_Config) String() string { func (*BalanceNode_Config) ProtoMessage() {} func (x *BalanceNode_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[113] + mi := &file_avs_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8476,7 +8647,7 @@ type BalanceNode_Output struct { func (x *BalanceNode_Output) Reset() { *x = BalanceNode_Output{} - mi := &file_avs_proto_msgTypes[114] + mi := &file_avs_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8488,7 +8659,7 @@ func (x *BalanceNode_Output) String() string { func (*BalanceNode_Output) ProtoMessage() {} func (x *BalanceNode_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[114] + mi := &file_avs_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8522,7 +8693,7 @@ type BranchNode_Condition struct { func (x *BranchNode_Condition) Reset() { *x = BranchNode_Condition{} - mi := &file_avs_proto_msgTypes[115] + mi := &file_avs_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8534,7 +8705,7 @@ func (x *BranchNode_Condition) String() string { func (*BranchNode_Condition) ProtoMessage() {} func (x *BranchNode_Condition) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[115] + mi := &file_avs_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8580,7 +8751,7 @@ type BranchNode_Config struct { func (x *BranchNode_Config) Reset() { *x = BranchNode_Config{} - mi := &file_avs_proto_msgTypes[116] + mi := &file_avs_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8592,7 +8763,7 @@ func (x *BranchNode_Config) String() string { func (*BranchNode_Config) ProtoMessage() {} func (x *BranchNode_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[116] + mi := &file_avs_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8627,7 +8798,7 @@ type BranchNode_Output struct { func (x *BranchNode_Output) Reset() { *x = BranchNode_Output{} - mi := &file_avs_proto_msgTypes[117] + mi := &file_avs_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8639,7 +8810,7 @@ func (x *BranchNode_Output) String() string { func (*BranchNode_Output) ProtoMessage() {} func (x *BranchNode_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[117] + mi := &file_avs_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8675,7 +8846,7 @@ type FilterNode_Config struct { func (x *FilterNode_Config) Reset() { *x = FilterNode_Config{} - mi := &file_avs_proto_msgTypes[118] + mi := &file_avs_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8687,7 +8858,7 @@ func (x *FilterNode_Config) String() string { func (*FilterNode_Config) ProtoMessage() {} func (x *FilterNode_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[118] + mi := &file_avs_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8727,7 +8898,7 @@ type FilterNode_Output struct { func (x *FilterNode_Output) Reset() { *x = FilterNode_Output{} - mi := &file_avs_proto_msgTypes[119] + mi := &file_avs_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8739,7 +8910,7 @@ func (x *FilterNode_Output) String() string { func (*FilterNode_Output) ProtoMessage() {} func (x *FilterNode_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[119] + mi := &file_avs_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8783,7 +8954,7 @@ type LoopNode_Config struct { func (x *LoopNode_Config) Reset() { *x = LoopNode_Config{} - mi := &file_avs_proto_msgTypes[120] + mi := &file_avs_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8795,7 +8966,7 @@ func (x *LoopNode_Config) String() string { func (*LoopNode_Config) ProtoMessage() {} func (x *LoopNode_Config) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[120] + mi := &file_avs_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8855,7 +9026,7 @@ type LoopNode_Output struct { func (x *LoopNode_Output) Reset() { *x = LoopNode_Output{} - mi := &file_avs_proto_msgTypes[121] + mi := &file_avs_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8867,7 +9038,7 @@ func (x *LoopNode_Output) String() string { func (*LoopNode_Output) ProtoMessage() {} func (x *LoopNode_Output) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[121] + mi := &file_avs_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8942,7 +9113,7 @@ type Execution_Step struct { func (x *Execution_Step) Reset() { *x = Execution_Step{} - mi := &file_avs_proto_msgTypes[122] + mi := &file_avs_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8954,7 +9125,7 @@ func (x *Execution_Step) String() string { func (*Execution_Step) ProtoMessage() {} func (x *Execution_Step) ProtoReflect() protoreflect.Message { - mi := &file_avs_proto_msgTypes[122] + mi := &file_avs_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9590,16 +9761,18 @@ const file_avs_proto_rawDesc = "" + "\vcustom_code\x18\x12 \x01(\v2\x1a.aggregator.CustomCodeNodeH\x00R\n" + "customCode\x123\n" + "\abalance\x18\x13 \x01(\v2\x17.aggregator.BalanceNodeH\x00R\abalanceB\v\n" + - "\ttask_type\"\xdb\x0e\n" + + "\ttask_type\"\x8a\x0f\n" + "\tExecution\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x19\n" + "\bstart_at\x18\x02 \x01(\x03R\astartAt\x12\x15\n" + "\x06end_at\x18\x03 \x01(\x03R\x05endAt\x123\n" + "\x06status\x18\x04 \x01(\x0e2\x1b.aggregator.ExecutionStatusR\x06status\x12\x14\n" + "\x05error\x18\x05 \x01(\tR\x05error\x12\x14\n" + - "\x05index\x18\x06 \x01(\x03R\x05index\x12$\n" + - "\x0etotal_gas_cost\x18\a \x01(\tR\ftotalGasCost\x12<\n" + - "\x0eautomation_fee\x18\t \x01(\v2\x15.aggregator.FeeAmountR\rautomationFee\x120\n" + + "\x05index\x18\x06 \x01(\x03R\x05index\x124\n" + + "\rexecution_fee\x18\a \x01(\v2\x0f.aggregator.FeeR\fexecutionFee\x12(\n" + + "\x04cogs\x18\t \x03(\v2\x14.aggregator.NodeCOGSR\x04cogs\x121\n" + + "\tvalue_fee\x18\n" + + " \x01(\v2\x14.aggregator.ValueFeeR\bvalueFee\x120\n" + "\x05steps\x18\b \x03(\v2\x1a.aggregator.Execution.StepR\x05steps\x1a\x94\f\n" + "\x04Step\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" + @@ -9982,46 +10155,49 @@ const file_avs_proto_rawDesc = "" + "\x11creation_required\x18\x01 \x01(\bR\x10creationRequired\x128\n" + "\fcreation_fee\x18\x02 \x01(\v2\x15.aggregator.FeeAmountR\vcreationFee\x12>\n" + "\x0finitial_funding\x18\x03 \x01(\v2\x15.aggregator.FeeAmountR\x0einitialFunding\x12%\n" + - "\x0ewallet_address\x18\x04 \x01(\tR\rwalletAddress\"\xf2\x02\n" + - "\rAutomationFee\x120\n" + - "\bbase_fee\x18\x01 \x01(\v2\x15.aggregator.FeeAmountR\abaseFee\x12<\n" + - "\x0emonitoring_fee\x18\x02 \x01(\v2\x15.aggregator.FeeAmountR\rmonitoringFee\x12:\n" + - "\rexecution_fee\x18\x03 \x01(\v2\x15.aggregator.FeeAmountR\fexecutionFee\x12!\n" + - "\ftrigger_type\x18\x04 \x01(\tR\vtriggerType\x121\n" + - "\x14estimated_executions\x18\x05 \x01(\x03R\x13estimatedExecutions\x12)\n" + - "\x10duration_minutes\x18\x06 \x01(\x03R\x0fdurationMinutes\x124\n" + - "\x16fee_calculation_method\x18\a \x01(\tR\x14feeCalculationMethod\"\x9e\x02\n" + + "\x0ewallet_address\x18\x04 \x01(\tR\rwalletAddress\"1\n" + + "\x03Fee\x12\x16\n" + + "\x06amount\x18\x01 \x01(\tR\x06amount\x12\x12\n" + + "\x04unit\x18\x02 \x01(\tR\x04unit\"A\n" + + "\vNativeToken\x12\x16\n" + + "\x06symbol\x18\x01 \x01(\tR\x06symbol\x12\x1a\n" + + "\bdecimals\x18\x02 \x01(\x05R\bdecimals\"\x80\x01\n" + + "\bNodeCOGS\x12\x17\n" + + "\anode_id\x18\x01 \x01(\tR\x06nodeId\x12\x1b\n" + + "\tcost_type\x18\x02 \x01(\tR\bcostType\x12!\n" + + "\x03fee\x18\x03 \x01(\v2\x0f.aggregator.FeeR\x03fee\x12\x1b\n" + + "\tgas_units\x18\x04 \x01(\tR\bgasUnits\"\xe8\x01\n" + + "\bValueFee\x12!\n" + + "\x03fee\x18\x01 \x01(\v2\x0f.aggregator.FeeR\x03fee\x12-\n" + + "\x04tier\x18\x02 \x01(\x0e2\x19.aggregator.ExecutionTierR\x04tier\x12\x1d\n" + + "\n" + + "value_base\x18\x03 \x01(\tR\tvalueBase\x123\n" + + "\x15classification_method\x18\x04 \x01(\tR\x14classificationMethod\x12\x1e\n" + + "\n" + + "confidence\x18\x05 \x01(\x02R\n" + + "confidence\x12\x16\n" + + "\x06reason\x18\x06 \x01(\tR\x06reason\"\xbb\x01\n" + "\vFeeDiscount\x12#\n" + "\rdiscount_type\x18\x01 \x01(\tR\fdiscountType\x12#\n" + - "\rdiscount_name\x18\x02 \x01(\tR\fdiscountName\x12\x1d\n" + - "\n" + - "applies_to\x18\x03 \x01(\tR\tappliesTo\x12/\n" + - "\x13discount_percentage\x18\x04 \x01(\x02R\x12discountPercentage\x12>\n" + - "\x0fdiscount_amount\x18\x05 \x01(\v2\x15.aggregator.FeeAmountR\x0ediscountAmount\x12\x1f\n" + - "\vexpiry_date\x18\x06 \x01(\tR\n" + + "\rdiscount_name\x18\x02 \x01(\tR\fdiscountName\x12+\n" + + "\bdiscount\x18\x03 \x01(\v2\x0f.aggregator.FeeR\bdiscount\x12\x1f\n" + + "\vexpiry_date\x18\x04 \x01(\tR\n" + "expiryDate\x12\x14\n" + - "\x05terms\x18\a \x01(\tR\x05terms\"\x87\x06\n" + + "\x05terms\x18\x05 \x01(\tR\x05terms\"\xda\x03\n" + "\x10EstimateFeesResp\x12\x18\n" + "\asuccess\x18\x01 \x01(\bR\asuccess\x12\x14\n" + "\x05error\x18\x02 \x01(\tR\x05error\x124\n" + "\n" + - "error_code\x18\x03 \x01(\x0e2\x15.aggregator.ErrorCodeR\terrorCode\x126\n" + - "\bgas_fees\x18\x04 \x01(\v2\x1b.aggregator.GasFeeBreakdownR\agasFees\x12B\n" + - "\x0fautomation_fees\x18\x05 \x01(\v2\x19.aggregator.AutomationFeeR\x0eautomationFees\x12G\n" + - "\rcreation_fees\x18\x06 \x01(\v2\".aggregator.SmartWalletCreationFeeR\fcreationFees\x124\n" + - "\n" + - "total_fees\x18\a \x01(\v2\x15.aggregator.FeeAmountR\ttotalFees\x125\n" + - "\tdiscounts\x18\b \x03(\v2\x17.aggregator.FeeDiscountR\tdiscounts\x12>\n" + - "\x0ftotal_discounts\x18\t \x01(\v2\x15.aggregator.FeeAmountR\x0etotalDiscounts\x126\n" + - "\vfinal_total\x18\n" + - " \x01(\v2\x15.aggregator.FeeAmountR\n" + - "finalTotal\x12!\n" + - "\festimated_at\x18\v \x01(\x03R\vestimatedAt\x12\x19\n" + - "\bchain_id\x18\f \x01(\tR\achainId\x12*\n" + - "\x11price_data_source\x18\r \x01(\tR\x0fpriceDataSource\x123\n" + - "\x16price_data_age_seconds\x18\x0e \x01(\x03R\x13priceDataAgeSeconds\x12\x1a\n" + - "\bwarnings\x18\x0f \x03(\tR\bwarnings\x12(\n" + - "\x0frecommendations\x18\x10 \x03(\tR\x0frecommendations\"\x80\x01\n" + + "error_code\x18\x03 \x01(\x0e2\x15.aggregator.ErrorCodeR\terrorCode\x12\x19\n" + + "\bchain_id\x18\x04 \x01(\tR\achainId\x12:\n" + + "\fnative_token\x18\x05 \x01(\v2\x17.aggregator.NativeTokenR\vnativeToken\x124\n" + + "\rexecution_fee\x18\x06 \x01(\v2\x0f.aggregator.FeeR\fexecutionFee\x12(\n" + + "\x04cogs\x18\a \x03(\v2\x14.aggregator.NodeCOGSR\x04cogs\x121\n" + + "\tvalue_fee\x18\b \x01(\v2\x14.aggregator.ValueFeeR\bvalueFee\x125\n" + + "\tdiscounts\x18\t \x03(\v2\x17.aggregator.FeeDiscountR\tdiscounts\x12#\n" + + "\rpricing_model\x18\n" + + " \x01(\tR\fpricingModel\x12\x1a\n" + + "\bwarnings\x18\v \x03(\tR\bwarnings\"\x80\x01\n" + "\x0eEventCondition\x12\x1d\n" + "\n" + "field_name\x18\x01 \x01(\tR\tfieldName\x12\x1a\n" + @@ -10048,7 +10224,12 @@ const file_avs_proto_rawDesc = "" + "\x10NODE_TYPE_FILTER\x10\b\x12\x12\n" + "\x0eNODE_TYPE_LOOP\x10\t\x12\x15\n" + "\x11NODE_TYPE_BALANCE\x10\n" + - "*K\n" + + "*q\n" + + "\rExecutionTier\x12\x1e\n" + + "\x1aEXECUTION_TIER_UNSPECIFIED\x10\x00\x12\x14\n" + + "\x10EXECUTION_TIER_1\x10\x01\x12\x14\n" + + "\x10EXECUTION_TIER_2\x10\x02\x12\x14\n" + + "\x10EXECUTION_TIER_3\x10\x03*K\n" + "\rExecutionMode\x12\x1d\n" + "\x19EXECUTION_MODE_SEQUENTIAL\x10\x00\x12\x1b\n" + "\x17EXECUTION_MODE_PARALLEL\x10\x01*g\n" + @@ -10159,386 +10340,390 @@ func file_avs_proto_rawDescGZIP() []byte { return file_avs_proto_rawDescData } -var file_avs_proto_enumTypes = make([]protoimpl.EnumInfo, 7) -var file_avs_proto_msgTypes = make([]protoimpl.MessageInfo, 130) +var file_avs_proto_enumTypes = make([]protoimpl.EnumInfo, 8) +var file_avs_proto_msgTypes = make([]protoimpl.MessageInfo, 133) var file_avs_proto_goTypes = []any{ (TriggerType)(0), // 0: aggregator.TriggerType (NodeType)(0), // 1: aggregator.NodeType - (ExecutionMode)(0), // 2: aggregator.ExecutionMode - (Lang)(0), // 3: aggregator.Lang - (ErrorCode)(0), // 4: aggregator.ErrorCode - (TaskStatus)(0), // 5: aggregator.TaskStatus - (ExecutionStatus)(0), // 6: aggregator.ExecutionStatus - (*TokenMetadata)(nil), // 7: aggregator.TokenMetadata - (*GetTokenMetadataReq)(nil), // 8: aggregator.GetTokenMetadataReq - (*GetTokenMetadataResp)(nil), // 9: aggregator.GetTokenMetadataResp - (*IdReq)(nil), // 10: aggregator.IdReq - (*FixedTimeTrigger)(nil), // 11: aggregator.FixedTimeTrigger - (*CronTrigger)(nil), // 12: aggregator.CronTrigger - (*BlockTrigger)(nil), // 13: aggregator.BlockTrigger - (*EventTrigger)(nil), // 14: aggregator.EventTrigger - (*ManualTrigger)(nil), // 15: aggregator.ManualTrigger - (*TaskTrigger)(nil), // 16: aggregator.TaskTrigger - (*ETHTransferNode)(nil), // 17: aggregator.ETHTransferNode - (*ContractWriteNode)(nil), // 18: aggregator.ContractWriteNode - (*ContractReadNode)(nil), // 19: aggregator.ContractReadNode - (*GraphQLQueryNode)(nil), // 20: aggregator.GraphQLQueryNode - (*RestAPINode)(nil), // 21: aggregator.RestAPINode - (*CustomCodeNode)(nil), // 22: aggregator.CustomCodeNode - (*BalanceNode)(nil), // 23: aggregator.BalanceNode - (*BranchNode)(nil), // 24: aggregator.BranchNode - (*FilterNode)(nil), // 25: aggregator.FilterNode - (*LoopNode)(nil), // 26: aggregator.LoopNode - (*TaskEdge)(nil), // 27: aggregator.TaskEdge - (*TaskNode)(nil), // 28: aggregator.TaskNode - (*Execution)(nil), // 29: aggregator.Execution - (*Task)(nil), // 30: aggregator.Task - (*CreateTaskReq)(nil), // 31: aggregator.CreateTaskReq - (*CreateTaskResp)(nil), // 32: aggregator.CreateTaskResp - (*NonceRequest)(nil), // 33: aggregator.NonceRequest - (*NonceResp)(nil), // 34: aggregator.NonceResp - (*ListWalletReq)(nil), // 35: aggregator.ListWalletReq - (*SmartWallet)(nil), // 36: aggregator.SmartWallet - (*ListWalletResp)(nil), // 37: aggregator.ListWalletResp - (*ListTasksReq)(nil), // 38: aggregator.ListTasksReq - (*ListTasksResp)(nil), // 39: aggregator.ListTasksResp - (*ListExecutionsReq)(nil), // 40: aggregator.ListExecutionsReq - (*ListExecutionsResp)(nil), // 41: aggregator.ListExecutionsResp - (*ExecutionReq)(nil), // 42: aggregator.ExecutionReq - (*ExecutionStatusResp)(nil), // 43: aggregator.ExecutionStatusResp - (*GetKeyReq)(nil), // 44: aggregator.GetKeyReq - (*KeyResp)(nil), // 45: aggregator.KeyResp - (*GetWalletReq)(nil), // 46: aggregator.GetWalletReq - (*GetWalletResp)(nil), // 47: aggregator.GetWalletResp - (*SetWalletReq)(nil), // 48: aggregator.SetWalletReq - (*WithdrawFundsReq)(nil), // 49: aggregator.WithdrawFundsReq - (*WithdrawFundsResp)(nil), // 50: aggregator.WithdrawFundsResp - (*TriggerTaskReq)(nil), // 51: aggregator.TriggerTaskReq - (*TriggerTaskResp)(nil), // 52: aggregator.TriggerTaskResp - (*CreateOrUpdateSecretReq)(nil), // 53: aggregator.CreateOrUpdateSecretReq - (*ListSecretsReq)(nil), // 54: aggregator.ListSecretsReq - (*PageInfo)(nil), // 55: aggregator.PageInfo - (*Secret)(nil), // 56: aggregator.Secret - (*ListSecretsResp)(nil), // 57: aggregator.ListSecretsResp - (*DeleteSecretReq)(nil), // 58: aggregator.DeleteSecretReq - (*DeleteSecretResp)(nil), // 59: aggregator.DeleteSecretResp - (*GetSignatureFormatReq)(nil), // 60: aggregator.GetSignatureFormatReq - (*GetSignatureFormatResp)(nil), // 61: aggregator.GetSignatureFormatResp - (*CreateSecretResp)(nil), // 62: aggregator.CreateSecretResp - (*UpdateSecretResp)(nil), // 63: aggregator.UpdateSecretResp - (*DeleteTaskResp)(nil), // 64: aggregator.DeleteTaskResp - (*SetTaskEnabledReq)(nil), // 65: aggregator.SetTaskEnabledReq - (*SetTaskEnabledResp)(nil), // 66: aggregator.SetTaskEnabledResp - (*GetWorkflowCountReq)(nil), // 67: aggregator.GetWorkflowCountReq - (*GetWorkflowCountResp)(nil), // 68: aggregator.GetWorkflowCountResp - (*GetExecutionCountReq)(nil), // 69: aggregator.GetExecutionCountReq - (*GetExecutionCountResp)(nil), // 70: aggregator.GetExecutionCountResp - (*GetExecutionStatsReq)(nil), // 71: aggregator.GetExecutionStatsReq - (*GetExecutionStatsResp)(nil), // 72: aggregator.GetExecutionStatsResp - (*RunNodeWithInputsReq)(nil), // 73: aggregator.RunNodeWithInputsReq - (*RunNodeWithInputsResp)(nil), // 74: aggregator.RunNodeWithInputsResp - (*RunTriggerReq)(nil), // 75: aggregator.RunTriggerReq - (*RunTriggerResp)(nil), // 76: aggregator.RunTriggerResp - (*SimulateTaskReq)(nil), // 77: aggregator.SimulateTaskReq - (*EstimateFeesReq)(nil), // 78: aggregator.EstimateFeesReq - (*FeeAmount)(nil), // 79: aggregator.FeeAmount - (*GasFeeBreakdown)(nil), // 80: aggregator.GasFeeBreakdown - (*GasOperationFee)(nil), // 81: aggregator.GasOperationFee - (*SmartWalletCreationFee)(nil), // 82: aggregator.SmartWalletCreationFee - (*AutomationFee)(nil), // 83: aggregator.AutomationFee - (*FeeDiscount)(nil), // 84: aggregator.FeeDiscount - (*EstimateFeesResp)(nil), // 85: aggregator.EstimateFeesResp - (*EventCondition)(nil), // 86: aggregator.EventCondition - (*FixedTimeTrigger_Config)(nil), // 87: aggregator.FixedTimeTrigger.Config - (*FixedTimeTrigger_Output)(nil), // 88: aggregator.FixedTimeTrigger.Output - (*CronTrigger_Config)(nil), // 89: aggregator.CronTrigger.Config - (*CronTrigger_Output)(nil), // 90: aggregator.CronTrigger.Output - (*BlockTrigger_Config)(nil), // 91: aggregator.BlockTrigger.Config - (*BlockTrigger_Output)(nil), // 92: aggregator.BlockTrigger.Output - (*EventTrigger_Query)(nil), // 93: aggregator.EventTrigger.Query - (*EventTrigger_MethodCall)(nil), // 94: aggregator.EventTrigger.MethodCall - (*EventTrigger_Config)(nil), // 95: aggregator.EventTrigger.Config - (*EventTrigger_Output)(nil), // 96: aggregator.EventTrigger.Output - (*ManualTrigger_Config)(nil), // 97: aggregator.ManualTrigger.Config - (*ManualTrigger_Output)(nil), // 98: aggregator.ManualTrigger.Output - nil, // 99: aggregator.ManualTrigger.Config.HeadersEntry - nil, // 100: aggregator.ManualTrigger.Config.PathParamsEntry - (*ETHTransferNode_Config)(nil), // 101: aggregator.ETHTransferNode.Config - (*ETHTransferNode_Output)(nil), // 102: aggregator.ETHTransferNode.Output - (*ContractWriteNode_Config)(nil), // 103: aggregator.ContractWriteNode.Config - (*ContractWriteNode_MethodCall)(nil), // 104: aggregator.ContractWriteNode.MethodCall - (*ContractWriteNode_Output)(nil), // 105: aggregator.ContractWriteNode.Output - (*ContractWriteNode_MethodResult)(nil), // 106: aggregator.ContractWriteNode.MethodResult - (*ContractReadNode_MethodCall)(nil), // 107: aggregator.ContractReadNode.MethodCall - (*ContractReadNode_Config)(nil), // 108: aggregator.ContractReadNode.Config - (*ContractReadNode_MethodResult)(nil), // 109: aggregator.ContractReadNode.MethodResult - (*ContractReadNode_Output)(nil), // 110: aggregator.ContractReadNode.Output - (*ContractReadNode_MethodResult_StructuredField)(nil), // 111: aggregator.ContractReadNode.MethodResult.StructuredField - (*GraphQLQueryNode_Config)(nil), // 112: aggregator.GraphQLQueryNode.Config - (*GraphQLQueryNode_Output)(nil), // 113: aggregator.GraphQLQueryNode.Output - nil, // 114: aggregator.GraphQLQueryNode.Config.VariablesEntry - (*RestAPINode_Config)(nil), // 115: aggregator.RestAPINode.Config - (*RestAPINode_Output)(nil), // 116: aggregator.RestAPINode.Output - nil, // 117: aggregator.RestAPINode.Config.HeadersEntry - (*CustomCodeNode_Config)(nil), // 118: aggregator.CustomCodeNode.Config - (*CustomCodeNode_Output)(nil), // 119: aggregator.CustomCodeNode.Output - (*BalanceNode_Config)(nil), // 120: aggregator.BalanceNode.Config - (*BalanceNode_Output)(nil), // 121: aggregator.BalanceNode.Output - (*BranchNode_Condition)(nil), // 122: aggregator.BranchNode.Condition - (*BranchNode_Config)(nil), // 123: aggregator.BranchNode.Config - (*BranchNode_Output)(nil), // 124: aggregator.BranchNode.Output - (*FilterNode_Config)(nil), // 125: aggregator.FilterNode.Config - (*FilterNode_Output)(nil), // 126: aggregator.FilterNode.Output - (*LoopNode_Config)(nil), // 127: aggregator.LoopNode.Config - (*LoopNode_Output)(nil), // 128: aggregator.LoopNode.Output - (*Execution_Step)(nil), // 129: aggregator.Execution.Step - nil, // 130: aggregator.Task.InputVariablesEntry - nil, // 131: aggregator.CreateTaskReq.InputVariablesEntry - nil, // 132: aggregator.TriggerTaskReq.TriggerInputEntry - nil, // 133: aggregator.RunNodeWithInputsReq.InputVariablesEntry - nil, // 134: aggregator.RunTriggerReq.TriggerInputEntry - nil, // 135: aggregator.SimulateTaskReq.InputVariablesEntry - nil, // 136: aggregator.EstimateFeesReq.InputVariablesEntry - (*structpb.Value)(nil), // 137: google.protobuf.Value + (ExecutionTier)(0), // 2: aggregator.ExecutionTier + (ExecutionMode)(0), // 3: aggregator.ExecutionMode + (Lang)(0), // 4: aggregator.Lang + (ErrorCode)(0), // 5: aggregator.ErrorCode + (TaskStatus)(0), // 6: aggregator.TaskStatus + (ExecutionStatus)(0), // 7: aggregator.ExecutionStatus + (*TokenMetadata)(nil), // 8: aggregator.TokenMetadata + (*GetTokenMetadataReq)(nil), // 9: aggregator.GetTokenMetadataReq + (*GetTokenMetadataResp)(nil), // 10: aggregator.GetTokenMetadataResp + (*IdReq)(nil), // 11: aggregator.IdReq + (*FixedTimeTrigger)(nil), // 12: aggregator.FixedTimeTrigger + (*CronTrigger)(nil), // 13: aggregator.CronTrigger + (*BlockTrigger)(nil), // 14: aggregator.BlockTrigger + (*EventTrigger)(nil), // 15: aggregator.EventTrigger + (*ManualTrigger)(nil), // 16: aggregator.ManualTrigger + (*TaskTrigger)(nil), // 17: aggregator.TaskTrigger + (*ETHTransferNode)(nil), // 18: aggregator.ETHTransferNode + (*ContractWriteNode)(nil), // 19: aggregator.ContractWriteNode + (*ContractReadNode)(nil), // 20: aggregator.ContractReadNode + (*GraphQLQueryNode)(nil), // 21: aggregator.GraphQLQueryNode + (*RestAPINode)(nil), // 22: aggregator.RestAPINode + (*CustomCodeNode)(nil), // 23: aggregator.CustomCodeNode + (*BalanceNode)(nil), // 24: aggregator.BalanceNode + (*BranchNode)(nil), // 25: aggregator.BranchNode + (*FilterNode)(nil), // 26: aggregator.FilterNode + (*LoopNode)(nil), // 27: aggregator.LoopNode + (*TaskEdge)(nil), // 28: aggregator.TaskEdge + (*TaskNode)(nil), // 29: aggregator.TaskNode + (*Execution)(nil), // 30: aggregator.Execution + (*Task)(nil), // 31: aggregator.Task + (*CreateTaskReq)(nil), // 32: aggregator.CreateTaskReq + (*CreateTaskResp)(nil), // 33: aggregator.CreateTaskResp + (*NonceRequest)(nil), // 34: aggregator.NonceRequest + (*NonceResp)(nil), // 35: aggregator.NonceResp + (*ListWalletReq)(nil), // 36: aggregator.ListWalletReq + (*SmartWallet)(nil), // 37: aggregator.SmartWallet + (*ListWalletResp)(nil), // 38: aggregator.ListWalletResp + (*ListTasksReq)(nil), // 39: aggregator.ListTasksReq + (*ListTasksResp)(nil), // 40: aggregator.ListTasksResp + (*ListExecutionsReq)(nil), // 41: aggregator.ListExecutionsReq + (*ListExecutionsResp)(nil), // 42: aggregator.ListExecutionsResp + (*ExecutionReq)(nil), // 43: aggregator.ExecutionReq + (*ExecutionStatusResp)(nil), // 44: aggregator.ExecutionStatusResp + (*GetKeyReq)(nil), // 45: aggregator.GetKeyReq + (*KeyResp)(nil), // 46: aggregator.KeyResp + (*GetWalletReq)(nil), // 47: aggregator.GetWalletReq + (*GetWalletResp)(nil), // 48: aggregator.GetWalletResp + (*SetWalletReq)(nil), // 49: aggregator.SetWalletReq + (*WithdrawFundsReq)(nil), // 50: aggregator.WithdrawFundsReq + (*WithdrawFundsResp)(nil), // 51: aggregator.WithdrawFundsResp + (*TriggerTaskReq)(nil), // 52: aggregator.TriggerTaskReq + (*TriggerTaskResp)(nil), // 53: aggregator.TriggerTaskResp + (*CreateOrUpdateSecretReq)(nil), // 54: aggregator.CreateOrUpdateSecretReq + (*ListSecretsReq)(nil), // 55: aggregator.ListSecretsReq + (*PageInfo)(nil), // 56: aggregator.PageInfo + (*Secret)(nil), // 57: aggregator.Secret + (*ListSecretsResp)(nil), // 58: aggregator.ListSecretsResp + (*DeleteSecretReq)(nil), // 59: aggregator.DeleteSecretReq + (*DeleteSecretResp)(nil), // 60: aggregator.DeleteSecretResp + (*GetSignatureFormatReq)(nil), // 61: aggregator.GetSignatureFormatReq + (*GetSignatureFormatResp)(nil), // 62: aggregator.GetSignatureFormatResp + (*CreateSecretResp)(nil), // 63: aggregator.CreateSecretResp + (*UpdateSecretResp)(nil), // 64: aggregator.UpdateSecretResp + (*DeleteTaskResp)(nil), // 65: aggregator.DeleteTaskResp + (*SetTaskEnabledReq)(nil), // 66: aggregator.SetTaskEnabledReq + (*SetTaskEnabledResp)(nil), // 67: aggregator.SetTaskEnabledResp + (*GetWorkflowCountReq)(nil), // 68: aggregator.GetWorkflowCountReq + (*GetWorkflowCountResp)(nil), // 69: aggregator.GetWorkflowCountResp + (*GetExecutionCountReq)(nil), // 70: aggregator.GetExecutionCountReq + (*GetExecutionCountResp)(nil), // 71: aggregator.GetExecutionCountResp + (*GetExecutionStatsReq)(nil), // 72: aggregator.GetExecutionStatsReq + (*GetExecutionStatsResp)(nil), // 73: aggregator.GetExecutionStatsResp + (*RunNodeWithInputsReq)(nil), // 74: aggregator.RunNodeWithInputsReq + (*RunNodeWithInputsResp)(nil), // 75: aggregator.RunNodeWithInputsResp + (*RunTriggerReq)(nil), // 76: aggregator.RunTriggerReq + (*RunTriggerResp)(nil), // 77: aggregator.RunTriggerResp + (*SimulateTaskReq)(nil), // 78: aggregator.SimulateTaskReq + (*EstimateFeesReq)(nil), // 79: aggregator.EstimateFeesReq + (*FeeAmount)(nil), // 80: aggregator.FeeAmount + (*GasFeeBreakdown)(nil), // 81: aggregator.GasFeeBreakdown + (*GasOperationFee)(nil), // 82: aggregator.GasOperationFee + (*SmartWalletCreationFee)(nil), // 83: aggregator.SmartWalletCreationFee + (*Fee)(nil), // 84: aggregator.Fee + (*NativeToken)(nil), // 85: aggregator.NativeToken + (*NodeCOGS)(nil), // 86: aggregator.NodeCOGS + (*ValueFee)(nil), // 87: aggregator.ValueFee + (*FeeDiscount)(nil), // 88: aggregator.FeeDiscount + (*EstimateFeesResp)(nil), // 89: aggregator.EstimateFeesResp + (*EventCondition)(nil), // 90: aggregator.EventCondition + (*FixedTimeTrigger_Config)(nil), // 91: aggregator.FixedTimeTrigger.Config + (*FixedTimeTrigger_Output)(nil), // 92: aggregator.FixedTimeTrigger.Output + (*CronTrigger_Config)(nil), // 93: aggregator.CronTrigger.Config + (*CronTrigger_Output)(nil), // 94: aggregator.CronTrigger.Output + (*BlockTrigger_Config)(nil), // 95: aggregator.BlockTrigger.Config + (*BlockTrigger_Output)(nil), // 96: aggregator.BlockTrigger.Output + (*EventTrigger_Query)(nil), // 97: aggregator.EventTrigger.Query + (*EventTrigger_MethodCall)(nil), // 98: aggregator.EventTrigger.MethodCall + (*EventTrigger_Config)(nil), // 99: aggregator.EventTrigger.Config + (*EventTrigger_Output)(nil), // 100: aggregator.EventTrigger.Output + (*ManualTrigger_Config)(nil), // 101: aggregator.ManualTrigger.Config + (*ManualTrigger_Output)(nil), // 102: aggregator.ManualTrigger.Output + nil, // 103: aggregator.ManualTrigger.Config.HeadersEntry + nil, // 104: aggregator.ManualTrigger.Config.PathParamsEntry + (*ETHTransferNode_Config)(nil), // 105: aggregator.ETHTransferNode.Config + (*ETHTransferNode_Output)(nil), // 106: aggregator.ETHTransferNode.Output + (*ContractWriteNode_Config)(nil), // 107: aggregator.ContractWriteNode.Config + (*ContractWriteNode_MethodCall)(nil), // 108: aggregator.ContractWriteNode.MethodCall + (*ContractWriteNode_Output)(nil), // 109: aggregator.ContractWriteNode.Output + (*ContractWriteNode_MethodResult)(nil), // 110: aggregator.ContractWriteNode.MethodResult + (*ContractReadNode_MethodCall)(nil), // 111: aggregator.ContractReadNode.MethodCall + (*ContractReadNode_Config)(nil), // 112: aggregator.ContractReadNode.Config + (*ContractReadNode_MethodResult)(nil), // 113: aggregator.ContractReadNode.MethodResult + (*ContractReadNode_Output)(nil), // 114: aggregator.ContractReadNode.Output + (*ContractReadNode_MethodResult_StructuredField)(nil), // 115: aggregator.ContractReadNode.MethodResult.StructuredField + (*GraphQLQueryNode_Config)(nil), // 116: aggregator.GraphQLQueryNode.Config + (*GraphQLQueryNode_Output)(nil), // 117: aggregator.GraphQLQueryNode.Output + nil, // 118: aggregator.GraphQLQueryNode.Config.VariablesEntry + (*RestAPINode_Config)(nil), // 119: aggregator.RestAPINode.Config + (*RestAPINode_Output)(nil), // 120: aggregator.RestAPINode.Output + nil, // 121: aggregator.RestAPINode.Config.HeadersEntry + (*CustomCodeNode_Config)(nil), // 122: aggregator.CustomCodeNode.Config + (*CustomCodeNode_Output)(nil), // 123: aggregator.CustomCodeNode.Output + (*BalanceNode_Config)(nil), // 124: aggregator.BalanceNode.Config + (*BalanceNode_Output)(nil), // 125: aggregator.BalanceNode.Output + (*BranchNode_Condition)(nil), // 126: aggregator.BranchNode.Condition + (*BranchNode_Config)(nil), // 127: aggregator.BranchNode.Config + (*BranchNode_Output)(nil), // 128: aggregator.BranchNode.Output + (*FilterNode_Config)(nil), // 129: aggregator.FilterNode.Config + (*FilterNode_Output)(nil), // 130: aggregator.FilterNode.Output + (*LoopNode_Config)(nil), // 131: aggregator.LoopNode.Config + (*LoopNode_Output)(nil), // 132: aggregator.LoopNode.Output + (*Execution_Step)(nil), // 133: aggregator.Execution.Step + nil, // 134: aggregator.Task.InputVariablesEntry + nil, // 135: aggregator.CreateTaskReq.InputVariablesEntry + nil, // 136: aggregator.TriggerTaskReq.TriggerInputEntry + nil, // 137: aggregator.RunNodeWithInputsReq.InputVariablesEntry + nil, // 138: aggregator.RunTriggerReq.TriggerInputEntry + nil, // 139: aggregator.SimulateTaskReq.InputVariablesEntry + nil, // 140: aggregator.EstimateFeesReq.InputVariablesEntry + (*structpb.Value)(nil), // 141: google.protobuf.Value } var file_avs_proto_depIdxs = []int32{ - 7, // 0: aggregator.GetTokenMetadataResp.token:type_name -> aggregator.TokenMetadata - 87, // 1: aggregator.FixedTimeTrigger.config:type_name -> aggregator.FixedTimeTrigger.Config - 89, // 2: aggregator.CronTrigger.config:type_name -> aggregator.CronTrigger.Config - 91, // 3: aggregator.BlockTrigger.config:type_name -> aggregator.BlockTrigger.Config - 95, // 4: aggregator.EventTrigger.config:type_name -> aggregator.EventTrigger.Config - 97, // 5: aggregator.ManualTrigger.config:type_name -> aggregator.ManualTrigger.Config + 8, // 0: aggregator.GetTokenMetadataResp.token:type_name -> aggregator.TokenMetadata + 91, // 1: aggregator.FixedTimeTrigger.config:type_name -> aggregator.FixedTimeTrigger.Config + 93, // 2: aggregator.CronTrigger.config:type_name -> aggregator.CronTrigger.Config + 95, // 3: aggregator.BlockTrigger.config:type_name -> aggregator.BlockTrigger.Config + 99, // 4: aggregator.EventTrigger.config:type_name -> aggregator.EventTrigger.Config + 101, // 5: aggregator.ManualTrigger.config:type_name -> aggregator.ManualTrigger.Config 0, // 6: aggregator.TaskTrigger.type:type_name -> aggregator.TriggerType - 15, // 7: aggregator.TaskTrigger.manual:type_name -> aggregator.ManualTrigger - 11, // 8: aggregator.TaskTrigger.fixed_time:type_name -> aggregator.FixedTimeTrigger - 12, // 9: aggregator.TaskTrigger.cron:type_name -> aggregator.CronTrigger - 13, // 10: aggregator.TaskTrigger.block:type_name -> aggregator.BlockTrigger - 14, // 11: aggregator.TaskTrigger.event:type_name -> aggregator.EventTrigger - 101, // 12: aggregator.ETHTransferNode.config:type_name -> aggregator.ETHTransferNode.Config - 103, // 13: aggregator.ContractWriteNode.config:type_name -> aggregator.ContractWriteNode.Config - 108, // 14: aggregator.ContractReadNode.config:type_name -> aggregator.ContractReadNode.Config - 112, // 15: aggregator.GraphQLQueryNode.config:type_name -> aggregator.GraphQLQueryNode.Config - 115, // 16: aggregator.RestAPINode.config:type_name -> aggregator.RestAPINode.Config - 118, // 17: aggregator.CustomCodeNode.config:type_name -> aggregator.CustomCodeNode.Config - 120, // 18: aggregator.BalanceNode.config:type_name -> aggregator.BalanceNode.Config - 123, // 19: aggregator.BranchNode.config:type_name -> aggregator.BranchNode.Config - 125, // 20: aggregator.FilterNode.config:type_name -> aggregator.FilterNode.Config - 17, // 21: aggregator.LoopNode.eth_transfer:type_name -> aggregator.ETHTransferNode - 18, // 22: aggregator.LoopNode.contract_write:type_name -> aggregator.ContractWriteNode - 19, // 23: aggregator.LoopNode.contract_read:type_name -> aggregator.ContractReadNode - 20, // 24: aggregator.LoopNode.graphql_data_query:type_name -> aggregator.GraphQLQueryNode - 21, // 25: aggregator.LoopNode.rest_api:type_name -> aggregator.RestAPINode - 22, // 26: aggregator.LoopNode.custom_code:type_name -> aggregator.CustomCodeNode - 127, // 27: aggregator.LoopNode.config:type_name -> aggregator.LoopNode.Config + 16, // 7: aggregator.TaskTrigger.manual:type_name -> aggregator.ManualTrigger + 12, // 8: aggregator.TaskTrigger.fixed_time:type_name -> aggregator.FixedTimeTrigger + 13, // 9: aggregator.TaskTrigger.cron:type_name -> aggregator.CronTrigger + 14, // 10: aggregator.TaskTrigger.block:type_name -> aggregator.BlockTrigger + 15, // 11: aggregator.TaskTrigger.event:type_name -> aggregator.EventTrigger + 105, // 12: aggregator.ETHTransferNode.config:type_name -> aggregator.ETHTransferNode.Config + 107, // 13: aggregator.ContractWriteNode.config:type_name -> aggregator.ContractWriteNode.Config + 112, // 14: aggregator.ContractReadNode.config:type_name -> aggregator.ContractReadNode.Config + 116, // 15: aggregator.GraphQLQueryNode.config:type_name -> aggregator.GraphQLQueryNode.Config + 119, // 16: aggregator.RestAPINode.config:type_name -> aggregator.RestAPINode.Config + 122, // 17: aggregator.CustomCodeNode.config:type_name -> aggregator.CustomCodeNode.Config + 124, // 18: aggregator.BalanceNode.config:type_name -> aggregator.BalanceNode.Config + 127, // 19: aggregator.BranchNode.config:type_name -> aggregator.BranchNode.Config + 129, // 20: aggregator.FilterNode.config:type_name -> aggregator.FilterNode.Config + 18, // 21: aggregator.LoopNode.eth_transfer:type_name -> aggregator.ETHTransferNode + 19, // 22: aggregator.LoopNode.contract_write:type_name -> aggregator.ContractWriteNode + 20, // 23: aggregator.LoopNode.contract_read:type_name -> aggregator.ContractReadNode + 21, // 24: aggregator.LoopNode.graphql_data_query:type_name -> aggregator.GraphQLQueryNode + 22, // 25: aggregator.LoopNode.rest_api:type_name -> aggregator.RestAPINode + 23, // 26: aggregator.LoopNode.custom_code:type_name -> aggregator.CustomCodeNode + 131, // 27: aggregator.LoopNode.config:type_name -> aggregator.LoopNode.Config 1, // 28: aggregator.TaskNode.type:type_name -> aggregator.NodeType - 17, // 29: aggregator.TaskNode.eth_transfer:type_name -> aggregator.ETHTransferNode - 18, // 30: aggregator.TaskNode.contract_write:type_name -> aggregator.ContractWriteNode - 19, // 31: aggregator.TaskNode.contract_read:type_name -> aggregator.ContractReadNode - 20, // 32: aggregator.TaskNode.graphql_query:type_name -> aggregator.GraphQLQueryNode - 21, // 33: aggregator.TaskNode.rest_api:type_name -> aggregator.RestAPINode - 24, // 34: aggregator.TaskNode.branch:type_name -> aggregator.BranchNode - 25, // 35: aggregator.TaskNode.filter:type_name -> aggregator.FilterNode - 26, // 36: aggregator.TaskNode.loop:type_name -> aggregator.LoopNode - 22, // 37: aggregator.TaskNode.custom_code:type_name -> aggregator.CustomCodeNode - 23, // 38: aggregator.TaskNode.balance:type_name -> aggregator.BalanceNode - 6, // 39: aggregator.Execution.status:type_name -> aggregator.ExecutionStatus - 79, // 40: aggregator.Execution.automation_fee:type_name -> aggregator.FeeAmount - 129, // 41: aggregator.Execution.steps:type_name -> aggregator.Execution.Step - 5, // 42: aggregator.Task.status:type_name -> aggregator.TaskStatus - 16, // 43: aggregator.Task.trigger:type_name -> aggregator.TaskTrigger - 28, // 44: aggregator.Task.nodes:type_name -> aggregator.TaskNode - 27, // 45: aggregator.Task.edges:type_name -> aggregator.TaskEdge - 130, // 46: aggregator.Task.input_variables:type_name -> aggregator.Task.InputVariablesEntry - 16, // 47: aggregator.CreateTaskReq.trigger:type_name -> aggregator.TaskTrigger - 28, // 48: aggregator.CreateTaskReq.nodes:type_name -> aggregator.TaskNode - 27, // 49: aggregator.CreateTaskReq.edges:type_name -> aggregator.TaskEdge - 131, // 50: aggregator.CreateTaskReq.input_variables:type_name -> aggregator.CreateTaskReq.InputVariablesEntry - 36, // 51: aggregator.ListWalletResp.items:type_name -> aggregator.SmartWallet - 30, // 52: aggregator.ListTasksResp.items:type_name -> aggregator.Task - 55, // 53: aggregator.ListTasksResp.page_info:type_name -> aggregator.PageInfo - 29, // 54: aggregator.ListExecutionsResp.items:type_name -> aggregator.Execution - 55, // 55: aggregator.ListExecutionsResp.page_info:type_name -> aggregator.PageInfo - 6, // 56: aggregator.ExecutionStatusResp.status:type_name -> aggregator.ExecutionStatus - 0, // 57: aggregator.TriggerTaskReq.trigger_type:type_name -> aggregator.TriggerType - 92, // 58: aggregator.TriggerTaskReq.block_trigger:type_name -> aggregator.BlockTrigger.Output - 88, // 59: aggregator.TriggerTaskReq.fixed_time_trigger:type_name -> aggregator.FixedTimeTrigger.Output - 90, // 60: aggregator.TriggerTaskReq.cron_trigger:type_name -> aggregator.CronTrigger.Output - 96, // 61: aggregator.TriggerTaskReq.event_trigger:type_name -> aggregator.EventTrigger.Output - 98, // 62: aggregator.TriggerTaskReq.manual_trigger:type_name -> aggregator.ManualTrigger.Output - 132, // 63: aggregator.TriggerTaskReq.trigger_input:type_name -> aggregator.TriggerTaskReq.TriggerInputEntry - 6, // 64: aggregator.TriggerTaskResp.status:type_name -> aggregator.ExecutionStatus - 129, // 65: aggregator.TriggerTaskResp.steps:type_name -> aggregator.Execution.Step - 56, // 66: aggregator.ListSecretsResp.items:type_name -> aggregator.Secret - 55, // 67: aggregator.ListSecretsResp.page_info:type_name -> aggregator.PageInfo - 28, // 68: aggregator.RunNodeWithInputsReq.node:type_name -> aggregator.TaskNode - 133, // 69: aggregator.RunNodeWithInputsReq.input_variables:type_name -> aggregator.RunNodeWithInputsReq.InputVariablesEntry - 137, // 70: aggregator.RunNodeWithInputsResp.metadata:type_name -> google.protobuf.Value - 137, // 71: aggregator.RunNodeWithInputsResp.execution_context:type_name -> google.protobuf.Value - 4, // 72: aggregator.RunNodeWithInputsResp.error_code:type_name -> aggregator.ErrorCode - 102, // 73: aggregator.RunNodeWithInputsResp.eth_transfer:type_name -> aggregator.ETHTransferNode.Output - 113, // 74: aggregator.RunNodeWithInputsResp.graphql:type_name -> aggregator.GraphQLQueryNode.Output - 110, // 75: aggregator.RunNodeWithInputsResp.contract_read:type_name -> aggregator.ContractReadNode.Output - 105, // 76: aggregator.RunNodeWithInputsResp.contract_write:type_name -> aggregator.ContractWriteNode.Output - 119, // 77: aggregator.RunNodeWithInputsResp.custom_code:type_name -> aggregator.CustomCodeNode.Output - 116, // 78: aggregator.RunNodeWithInputsResp.rest_api:type_name -> aggregator.RestAPINode.Output - 124, // 79: aggregator.RunNodeWithInputsResp.branch:type_name -> aggregator.BranchNode.Output - 126, // 80: aggregator.RunNodeWithInputsResp.filter:type_name -> aggregator.FilterNode.Output - 128, // 81: aggregator.RunNodeWithInputsResp.loop:type_name -> aggregator.LoopNode.Output - 121, // 82: aggregator.RunNodeWithInputsResp.balance:type_name -> aggregator.BalanceNode.Output - 16, // 83: aggregator.RunTriggerReq.trigger:type_name -> aggregator.TaskTrigger - 134, // 84: aggregator.RunTriggerReq.trigger_input:type_name -> aggregator.RunTriggerReq.TriggerInputEntry - 137, // 85: aggregator.RunTriggerResp.metadata:type_name -> google.protobuf.Value - 137, // 86: aggregator.RunTriggerResp.execution_context:type_name -> google.protobuf.Value - 4, // 87: aggregator.RunTriggerResp.error_code:type_name -> aggregator.ErrorCode - 92, // 88: aggregator.RunTriggerResp.block_trigger:type_name -> aggregator.BlockTrigger.Output - 88, // 89: aggregator.RunTriggerResp.fixed_time_trigger:type_name -> aggregator.FixedTimeTrigger.Output - 90, // 90: aggregator.RunTriggerResp.cron_trigger:type_name -> aggregator.CronTrigger.Output - 96, // 91: aggregator.RunTriggerResp.event_trigger:type_name -> aggregator.EventTrigger.Output - 98, // 92: aggregator.RunTriggerResp.manual_trigger:type_name -> aggregator.ManualTrigger.Output - 16, // 93: aggregator.SimulateTaskReq.trigger:type_name -> aggregator.TaskTrigger - 28, // 94: aggregator.SimulateTaskReq.nodes:type_name -> aggregator.TaskNode - 27, // 95: aggregator.SimulateTaskReq.edges:type_name -> aggregator.TaskEdge - 135, // 96: aggregator.SimulateTaskReq.input_variables:type_name -> aggregator.SimulateTaskReq.InputVariablesEntry - 16, // 97: aggregator.EstimateFeesReq.trigger:type_name -> aggregator.TaskTrigger - 28, // 98: aggregator.EstimateFeesReq.nodes:type_name -> aggregator.TaskNode - 27, // 99: aggregator.EstimateFeesReq.edges:type_name -> aggregator.TaskEdge - 136, // 100: aggregator.EstimateFeesReq.input_variables:type_name -> aggregator.EstimateFeesReq.InputVariablesEntry - 79, // 101: aggregator.GasFeeBreakdown.total_gas_fees:type_name -> aggregator.FeeAmount - 81, // 102: aggregator.GasFeeBreakdown.operations:type_name -> aggregator.GasOperationFee - 79, // 103: aggregator.GasOperationFee.fee:type_name -> aggregator.FeeAmount - 79, // 104: aggregator.SmartWalletCreationFee.creation_fee:type_name -> aggregator.FeeAmount - 79, // 105: aggregator.SmartWalletCreationFee.initial_funding:type_name -> aggregator.FeeAmount - 79, // 106: aggregator.AutomationFee.base_fee:type_name -> aggregator.FeeAmount - 79, // 107: aggregator.AutomationFee.monitoring_fee:type_name -> aggregator.FeeAmount - 79, // 108: aggregator.AutomationFee.execution_fee:type_name -> aggregator.FeeAmount - 79, // 109: aggregator.FeeDiscount.discount_amount:type_name -> aggregator.FeeAmount - 4, // 110: aggregator.EstimateFeesResp.error_code:type_name -> aggregator.ErrorCode - 80, // 111: aggregator.EstimateFeesResp.gas_fees:type_name -> aggregator.GasFeeBreakdown - 83, // 112: aggregator.EstimateFeesResp.automation_fees:type_name -> aggregator.AutomationFee - 82, // 113: aggregator.EstimateFeesResp.creation_fees:type_name -> aggregator.SmartWalletCreationFee - 79, // 114: aggregator.EstimateFeesResp.total_fees:type_name -> aggregator.FeeAmount - 84, // 115: aggregator.EstimateFeesResp.discounts:type_name -> aggregator.FeeDiscount - 79, // 116: aggregator.EstimateFeesResp.total_discounts:type_name -> aggregator.FeeAmount - 79, // 117: aggregator.EstimateFeesResp.final_total:type_name -> aggregator.FeeAmount - 137, // 118: aggregator.FixedTimeTrigger.Output.data:type_name -> google.protobuf.Value - 137, // 119: aggregator.CronTrigger.Output.data:type_name -> google.protobuf.Value - 137, // 120: aggregator.BlockTrigger.Output.data:type_name -> google.protobuf.Value - 137, // 121: aggregator.EventTrigger.Query.contract_abi:type_name -> google.protobuf.Value - 86, // 122: aggregator.EventTrigger.Query.conditions:type_name -> aggregator.EventCondition - 94, // 123: aggregator.EventTrigger.Query.method_calls:type_name -> aggregator.EventTrigger.MethodCall - 93, // 124: aggregator.EventTrigger.Config.queries:type_name -> aggregator.EventTrigger.Query - 137, // 125: aggregator.EventTrigger.Output.data:type_name -> google.protobuf.Value - 137, // 126: aggregator.ManualTrigger.Config.data:type_name -> google.protobuf.Value - 99, // 127: aggregator.ManualTrigger.Config.headers:type_name -> aggregator.ManualTrigger.Config.HeadersEntry - 100, // 128: aggregator.ManualTrigger.Config.pathParams:type_name -> aggregator.ManualTrigger.Config.PathParamsEntry - 3, // 129: aggregator.ManualTrigger.Config.lang:type_name -> aggregator.Lang - 137, // 130: aggregator.ManualTrigger.Output.data:type_name -> google.protobuf.Value - 137, // 131: aggregator.ETHTransferNode.Output.data:type_name -> google.protobuf.Value - 137, // 132: aggregator.ContractWriteNode.Config.contract_abi:type_name -> google.protobuf.Value - 104, // 133: aggregator.ContractWriteNode.Config.method_calls:type_name -> aggregator.ContractWriteNode.MethodCall - 137, // 134: aggregator.ContractWriteNode.Output.data:type_name -> google.protobuf.Value - 137, // 135: aggregator.ContractWriteNode.MethodResult.method_abi:type_name -> google.protobuf.Value - 137, // 136: aggregator.ContractWriteNode.MethodResult.receipt:type_name -> google.protobuf.Value - 137, // 137: aggregator.ContractWriteNode.MethodResult.value:type_name -> google.protobuf.Value - 137, // 138: aggregator.ContractReadNode.Config.contract_abi:type_name -> google.protobuf.Value - 107, // 139: aggregator.ContractReadNode.Config.method_calls:type_name -> aggregator.ContractReadNode.MethodCall - 111, // 140: aggregator.ContractReadNode.MethodResult.data:type_name -> aggregator.ContractReadNode.MethodResult.StructuredField - 137, // 141: aggregator.ContractReadNode.Output.data:type_name -> google.protobuf.Value - 114, // 142: aggregator.GraphQLQueryNode.Config.variables:type_name -> aggregator.GraphQLQueryNode.Config.VariablesEntry - 137, // 143: aggregator.GraphQLQueryNode.Output.data:type_name -> google.protobuf.Value - 117, // 144: aggregator.RestAPINode.Config.headers:type_name -> aggregator.RestAPINode.Config.HeadersEntry - 137, // 145: aggregator.RestAPINode.Config.options:type_name -> google.protobuf.Value - 137, // 146: aggregator.RestAPINode.Output.data:type_name -> google.protobuf.Value - 3, // 147: aggregator.CustomCodeNode.Config.lang:type_name -> aggregator.Lang - 137, // 148: aggregator.CustomCodeNode.Output.data:type_name -> google.protobuf.Value - 137, // 149: aggregator.BalanceNode.Output.data:type_name -> google.protobuf.Value - 122, // 150: aggregator.BranchNode.Config.conditions:type_name -> aggregator.BranchNode.Condition - 137, // 151: aggregator.BranchNode.Output.data:type_name -> google.protobuf.Value - 137, // 152: aggregator.FilterNode.Output.data:type_name -> google.protobuf.Value - 2, // 153: aggregator.LoopNode.Config.execution_mode:type_name -> aggregator.ExecutionMode - 137, // 154: aggregator.LoopNode.Output.data:type_name -> google.protobuf.Value - 4, // 155: aggregator.Execution.Step.error_code:type_name -> aggregator.ErrorCode - 137, // 156: aggregator.Execution.Step.config:type_name -> google.protobuf.Value - 137, // 157: aggregator.Execution.Step.metadata:type_name -> google.protobuf.Value - 137, // 158: aggregator.Execution.Step.execution_context:type_name -> google.protobuf.Value - 92, // 159: aggregator.Execution.Step.block_trigger:type_name -> aggregator.BlockTrigger.Output - 88, // 160: aggregator.Execution.Step.fixed_time_trigger:type_name -> aggregator.FixedTimeTrigger.Output - 90, // 161: aggregator.Execution.Step.cron_trigger:type_name -> aggregator.CronTrigger.Output - 96, // 162: aggregator.Execution.Step.event_trigger:type_name -> aggregator.EventTrigger.Output - 98, // 163: aggregator.Execution.Step.manual_trigger:type_name -> aggregator.ManualTrigger.Output - 102, // 164: aggregator.Execution.Step.eth_transfer:type_name -> aggregator.ETHTransferNode.Output - 113, // 165: aggregator.Execution.Step.graphql:type_name -> aggregator.GraphQLQueryNode.Output - 110, // 166: aggregator.Execution.Step.contract_read:type_name -> aggregator.ContractReadNode.Output - 105, // 167: aggregator.Execution.Step.contract_write:type_name -> aggregator.ContractWriteNode.Output - 119, // 168: aggregator.Execution.Step.custom_code:type_name -> aggregator.CustomCodeNode.Output - 116, // 169: aggregator.Execution.Step.rest_api:type_name -> aggregator.RestAPINode.Output - 124, // 170: aggregator.Execution.Step.branch:type_name -> aggregator.BranchNode.Output - 126, // 171: aggregator.Execution.Step.filter:type_name -> aggregator.FilterNode.Output - 128, // 172: aggregator.Execution.Step.loop:type_name -> aggregator.LoopNode.Output - 121, // 173: aggregator.Execution.Step.balance:type_name -> aggregator.BalanceNode.Output - 137, // 174: aggregator.Task.InputVariablesEntry.value:type_name -> google.protobuf.Value - 137, // 175: aggregator.CreateTaskReq.InputVariablesEntry.value:type_name -> google.protobuf.Value - 137, // 176: aggregator.TriggerTaskReq.TriggerInputEntry.value:type_name -> google.protobuf.Value - 137, // 177: aggregator.RunNodeWithInputsReq.InputVariablesEntry.value:type_name -> google.protobuf.Value - 137, // 178: aggregator.RunTriggerReq.TriggerInputEntry.value:type_name -> google.protobuf.Value - 137, // 179: aggregator.SimulateTaskReq.InputVariablesEntry.value:type_name -> google.protobuf.Value - 137, // 180: aggregator.EstimateFeesReq.InputVariablesEntry.value:type_name -> google.protobuf.Value - 44, // 181: aggregator.Aggregator.GetKey:input_type -> aggregator.GetKeyReq - 60, // 182: aggregator.Aggregator.GetSignatureFormat:input_type -> aggregator.GetSignatureFormatReq - 33, // 183: aggregator.Aggregator.GetNonce:input_type -> aggregator.NonceRequest - 46, // 184: aggregator.Aggregator.GetWallet:input_type -> aggregator.GetWalletReq - 48, // 185: aggregator.Aggregator.SetWallet:input_type -> aggregator.SetWalletReq - 35, // 186: aggregator.Aggregator.ListWallets:input_type -> aggregator.ListWalletReq - 49, // 187: aggregator.Aggregator.WithdrawFunds:input_type -> aggregator.WithdrawFundsReq - 31, // 188: aggregator.Aggregator.CreateTask:input_type -> aggregator.CreateTaskReq - 38, // 189: aggregator.Aggregator.ListTasks:input_type -> aggregator.ListTasksReq - 10, // 190: aggregator.Aggregator.GetTask:input_type -> aggregator.IdReq - 40, // 191: aggregator.Aggregator.ListExecutions:input_type -> aggregator.ListExecutionsReq - 42, // 192: aggregator.Aggregator.GetExecution:input_type -> aggregator.ExecutionReq - 42, // 193: aggregator.Aggregator.GetExecutionStatus:input_type -> aggregator.ExecutionReq - 65, // 194: aggregator.Aggregator.SetTaskEnabled:input_type -> aggregator.SetTaskEnabledReq - 10, // 195: aggregator.Aggregator.DeleteTask:input_type -> aggregator.IdReq - 51, // 196: aggregator.Aggregator.TriggerTask:input_type -> aggregator.TriggerTaskReq - 53, // 197: aggregator.Aggregator.CreateSecret:input_type -> aggregator.CreateOrUpdateSecretReq - 58, // 198: aggregator.Aggregator.DeleteSecret:input_type -> aggregator.DeleteSecretReq - 54, // 199: aggregator.Aggregator.ListSecrets:input_type -> aggregator.ListSecretsReq - 53, // 200: aggregator.Aggregator.UpdateSecret:input_type -> aggregator.CreateOrUpdateSecretReq - 67, // 201: aggregator.Aggregator.GetWorkflowCount:input_type -> aggregator.GetWorkflowCountReq - 69, // 202: aggregator.Aggregator.GetExecutionCount:input_type -> aggregator.GetExecutionCountReq - 71, // 203: aggregator.Aggregator.GetExecutionStats:input_type -> aggregator.GetExecutionStatsReq - 73, // 204: aggregator.Aggregator.RunNodeWithInputs:input_type -> aggregator.RunNodeWithInputsReq - 75, // 205: aggregator.Aggregator.RunTrigger:input_type -> aggregator.RunTriggerReq - 77, // 206: aggregator.Aggregator.SimulateTask:input_type -> aggregator.SimulateTaskReq - 8, // 207: aggregator.Aggregator.GetTokenMetadata:input_type -> aggregator.GetTokenMetadataReq - 78, // 208: aggregator.Aggregator.EstimateFees:input_type -> aggregator.EstimateFeesReq - 45, // 209: aggregator.Aggregator.GetKey:output_type -> aggregator.KeyResp - 61, // 210: aggregator.Aggregator.GetSignatureFormat:output_type -> aggregator.GetSignatureFormatResp - 34, // 211: aggregator.Aggregator.GetNonce:output_type -> aggregator.NonceResp - 47, // 212: aggregator.Aggregator.GetWallet:output_type -> aggregator.GetWalletResp - 47, // 213: aggregator.Aggregator.SetWallet:output_type -> aggregator.GetWalletResp - 37, // 214: aggregator.Aggregator.ListWallets:output_type -> aggregator.ListWalletResp - 50, // 215: aggregator.Aggregator.WithdrawFunds:output_type -> aggregator.WithdrawFundsResp - 32, // 216: aggregator.Aggregator.CreateTask:output_type -> aggregator.CreateTaskResp - 39, // 217: aggregator.Aggregator.ListTasks:output_type -> aggregator.ListTasksResp - 30, // 218: aggregator.Aggregator.GetTask:output_type -> aggregator.Task - 41, // 219: aggregator.Aggregator.ListExecutions:output_type -> aggregator.ListExecutionsResp - 29, // 220: aggregator.Aggregator.GetExecution:output_type -> aggregator.Execution - 43, // 221: aggregator.Aggregator.GetExecutionStatus:output_type -> aggregator.ExecutionStatusResp - 66, // 222: aggregator.Aggregator.SetTaskEnabled:output_type -> aggregator.SetTaskEnabledResp - 64, // 223: aggregator.Aggregator.DeleteTask:output_type -> aggregator.DeleteTaskResp - 52, // 224: aggregator.Aggregator.TriggerTask:output_type -> aggregator.TriggerTaskResp - 62, // 225: aggregator.Aggregator.CreateSecret:output_type -> aggregator.CreateSecretResp - 59, // 226: aggregator.Aggregator.DeleteSecret:output_type -> aggregator.DeleteSecretResp - 57, // 227: aggregator.Aggregator.ListSecrets:output_type -> aggregator.ListSecretsResp - 63, // 228: aggregator.Aggregator.UpdateSecret:output_type -> aggregator.UpdateSecretResp - 68, // 229: aggregator.Aggregator.GetWorkflowCount:output_type -> aggregator.GetWorkflowCountResp - 70, // 230: aggregator.Aggregator.GetExecutionCount:output_type -> aggregator.GetExecutionCountResp - 72, // 231: aggregator.Aggregator.GetExecutionStats:output_type -> aggregator.GetExecutionStatsResp - 74, // 232: aggregator.Aggregator.RunNodeWithInputs:output_type -> aggregator.RunNodeWithInputsResp - 76, // 233: aggregator.Aggregator.RunTrigger:output_type -> aggregator.RunTriggerResp - 29, // 234: aggregator.Aggregator.SimulateTask:output_type -> aggregator.Execution - 9, // 235: aggregator.Aggregator.GetTokenMetadata:output_type -> aggregator.GetTokenMetadataResp - 85, // 236: aggregator.Aggregator.EstimateFees:output_type -> aggregator.EstimateFeesResp + 18, // 29: aggregator.TaskNode.eth_transfer:type_name -> aggregator.ETHTransferNode + 19, // 30: aggregator.TaskNode.contract_write:type_name -> aggregator.ContractWriteNode + 20, // 31: aggregator.TaskNode.contract_read:type_name -> aggregator.ContractReadNode + 21, // 32: aggregator.TaskNode.graphql_query:type_name -> aggregator.GraphQLQueryNode + 22, // 33: aggregator.TaskNode.rest_api:type_name -> aggregator.RestAPINode + 25, // 34: aggregator.TaskNode.branch:type_name -> aggregator.BranchNode + 26, // 35: aggregator.TaskNode.filter:type_name -> aggregator.FilterNode + 27, // 36: aggregator.TaskNode.loop:type_name -> aggregator.LoopNode + 23, // 37: aggregator.TaskNode.custom_code:type_name -> aggregator.CustomCodeNode + 24, // 38: aggregator.TaskNode.balance:type_name -> aggregator.BalanceNode + 7, // 39: aggregator.Execution.status:type_name -> aggregator.ExecutionStatus + 84, // 40: aggregator.Execution.execution_fee:type_name -> aggregator.Fee + 86, // 41: aggregator.Execution.cogs:type_name -> aggregator.NodeCOGS + 87, // 42: aggregator.Execution.value_fee:type_name -> aggregator.ValueFee + 133, // 43: aggregator.Execution.steps:type_name -> aggregator.Execution.Step + 6, // 44: aggregator.Task.status:type_name -> aggregator.TaskStatus + 17, // 45: aggregator.Task.trigger:type_name -> aggregator.TaskTrigger + 29, // 46: aggregator.Task.nodes:type_name -> aggregator.TaskNode + 28, // 47: aggregator.Task.edges:type_name -> aggregator.TaskEdge + 134, // 48: aggregator.Task.input_variables:type_name -> aggregator.Task.InputVariablesEntry + 17, // 49: aggregator.CreateTaskReq.trigger:type_name -> aggregator.TaskTrigger + 29, // 50: aggregator.CreateTaskReq.nodes:type_name -> aggregator.TaskNode + 28, // 51: aggregator.CreateTaskReq.edges:type_name -> aggregator.TaskEdge + 135, // 52: aggregator.CreateTaskReq.input_variables:type_name -> aggregator.CreateTaskReq.InputVariablesEntry + 37, // 53: aggregator.ListWalletResp.items:type_name -> aggregator.SmartWallet + 31, // 54: aggregator.ListTasksResp.items:type_name -> aggregator.Task + 56, // 55: aggregator.ListTasksResp.page_info:type_name -> aggregator.PageInfo + 30, // 56: aggregator.ListExecutionsResp.items:type_name -> aggregator.Execution + 56, // 57: aggregator.ListExecutionsResp.page_info:type_name -> aggregator.PageInfo + 7, // 58: aggregator.ExecutionStatusResp.status:type_name -> aggregator.ExecutionStatus + 0, // 59: aggregator.TriggerTaskReq.trigger_type:type_name -> aggregator.TriggerType + 96, // 60: aggregator.TriggerTaskReq.block_trigger:type_name -> aggregator.BlockTrigger.Output + 92, // 61: aggregator.TriggerTaskReq.fixed_time_trigger:type_name -> aggregator.FixedTimeTrigger.Output + 94, // 62: aggregator.TriggerTaskReq.cron_trigger:type_name -> aggregator.CronTrigger.Output + 100, // 63: aggregator.TriggerTaskReq.event_trigger:type_name -> aggregator.EventTrigger.Output + 102, // 64: aggregator.TriggerTaskReq.manual_trigger:type_name -> aggregator.ManualTrigger.Output + 136, // 65: aggregator.TriggerTaskReq.trigger_input:type_name -> aggregator.TriggerTaskReq.TriggerInputEntry + 7, // 66: aggregator.TriggerTaskResp.status:type_name -> aggregator.ExecutionStatus + 133, // 67: aggregator.TriggerTaskResp.steps:type_name -> aggregator.Execution.Step + 57, // 68: aggregator.ListSecretsResp.items:type_name -> aggregator.Secret + 56, // 69: aggregator.ListSecretsResp.page_info:type_name -> aggregator.PageInfo + 29, // 70: aggregator.RunNodeWithInputsReq.node:type_name -> aggregator.TaskNode + 137, // 71: aggregator.RunNodeWithInputsReq.input_variables:type_name -> aggregator.RunNodeWithInputsReq.InputVariablesEntry + 141, // 72: aggregator.RunNodeWithInputsResp.metadata:type_name -> google.protobuf.Value + 141, // 73: aggregator.RunNodeWithInputsResp.execution_context:type_name -> google.protobuf.Value + 5, // 74: aggregator.RunNodeWithInputsResp.error_code:type_name -> aggregator.ErrorCode + 106, // 75: aggregator.RunNodeWithInputsResp.eth_transfer:type_name -> aggregator.ETHTransferNode.Output + 117, // 76: aggregator.RunNodeWithInputsResp.graphql:type_name -> aggregator.GraphQLQueryNode.Output + 114, // 77: aggregator.RunNodeWithInputsResp.contract_read:type_name -> aggregator.ContractReadNode.Output + 109, // 78: aggregator.RunNodeWithInputsResp.contract_write:type_name -> aggregator.ContractWriteNode.Output + 123, // 79: aggregator.RunNodeWithInputsResp.custom_code:type_name -> aggregator.CustomCodeNode.Output + 120, // 80: aggregator.RunNodeWithInputsResp.rest_api:type_name -> aggregator.RestAPINode.Output + 128, // 81: aggregator.RunNodeWithInputsResp.branch:type_name -> aggregator.BranchNode.Output + 130, // 82: aggregator.RunNodeWithInputsResp.filter:type_name -> aggregator.FilterNode.Output + 132, // 83: aggregator.RunNodeWithInputsResp.loop:type_name -> aggregator.LoopNode.Output + 125, // 84: aggregator.RunNodeWithInputsResp.balance:type_name -> aggregator.BalanceNode.Output + 17, // 85: aggregator.RunTriggerReq.trigger:type_name -> aggregator.TaskTrigger + 138, // 86: aggregator.RunTriggerReq.trigger_input:type_name -> aggregator.RunTriggerReq.TriggerInputEntry + 141, // 87: aggregator.RunTriggerResp.metadata:type_name -> google.protobuf.Value + 141, // 88: aggregator.RunTriggerResp.execution_context:type_name -> google.protobuf.Value + 5, // 89: aggregator.RunTriggerResp.error_code:type_name -> aggregator.ErrorCode + 96, // 90: aggregator.RunTriggerResp.block_trigger:type_name -> aggregator.BlockTrigger.Output + 92, // 91: aggregator.RunTriggerResp.fixed_time_trigger:type_name -> aggregator.FixedTimeTrigger.Output + 94, // 92: aggregator.RunTriggerResp.cron_trigger:type_name -> aggregator.CronTrigger.Output + 100, // 93: aggregator.RunTriggerResp.event_trigger:type_name -> aggregator.EventTrigger.Output + 102, // 94: aggregator.RunTriggerResp.manual_trigger:type_name -> aggregator.ManualTrigger.Output + 17, // 95: aggregator.SimulateTaskReq.trigger:type_name -> aggregator.TaskTrigger + 29, // 96: aggregator.SimulateTaskReq.nodes:type_name -> aggregator.TaskNode + 28, // 97: aggregator.SimulateTaskReq.edges:type_name -> aggregator.TaskEdge + 139, // 98: aggregator.SimulateTaskReq.input_variables:type_name -> aggregator.SimulateTaskReq.InputVariablesEntry + 17, // 99: aggregator.EstimateFeesReq.trigger:type_name -> aggregator.TaskTrigger + 29, // 100: aggregator.EstimateFeesReq.nodes:type_name -> aggregator.TaskNode + 28, // 101: aggregator.EstimateFeesReq.edges:type_name -> aggregator.TaskEdge + 140, // 102: aggregator.EstimateFeesReq.input_variables:type_name -> aggregator.EstimateFeesReq.InputVariablesEntry + 80, // 103: aggregator.GasFeeBreakdown.total_gas_fees:type_name -> aggregator.FeeAmount + 82, // 104: aggregator.GasFeeBreakdown.operations:type_name -> aggregator.GasOperationFee + 80, // 105: aggregator.GasOperationFee.fee:type_name -> aggregator.FeeAmount + 80, // 106: aggregator.SmartWalletCreationFee.creation_fee:type_name -> aggregator.FeeAmount + 80, // 107: aggregator.SmartWalletCreationFee.initial_funding:type_name -> aggregator.FeeAmount + 84, // 108: aggregator.NodeCOGS.fee:type_name -> aggregator.Fee + 84, // 109: aggregator.ValueFee.fee:type_name -> aggregator.Fee + 2, // 110: aggregator.ValueFee.tier:type_name -> aggregator.ExecutionTier + 84, // 111: aggregator.FeeDiscount.discount:type_name -> aggregator.Fee + 5, // 112: aggregator.EstimateFeesResp.error_code:type_name -> aggregator.ErrorCode + 85, // 113: aggregator.EstimateFeesResp.native_token:type_name -> aggregator.NativeToken + 84, // 114: aggregator.EstimateFeesResp.execution_fee:type_name -> aggregator.Fee + 86, // 115: aggregator.EstimateFeesResp.cogs:type_name -> aggregator.NodeCOGS + 87, // 116: aggregator.EstimateFeesResp.value_fee:type_name -> aggregator.ValueFee + 88, // 117: aggregator.EstimateFeesResp.discounts:type_name -> aggregator.FeeDiscount + 141, // 118: aggregator.FixedTimeTrigger.Output.data:type_name -> google.protobuf.Value + 141, // 119: aggregator.CronTrigger.Output.data:type_name -> google.protobuf.Value + 141, // 120: aggregator.BlockTrigger.Output.data:type_name -> google.protobuf.Value + 141, // 121: aggregator.EventTrigger.Query.contract_abi:type_name -> google.protobuf.Value + 90, // 122: aggregator.EventTrigger.Query.conditions:type_name -> aggregator.EventCondition + 98, // 123: aggregator.EventTrigger.Query.method_calls:type_name -> aggregator.EventTrigger.MethodCall + 97, // 124: aggregator.EventTrigger.Config.queries:type_name -> aggregator.EventTrigger.Query + 141, // 125: aggregator.EventTrigger.Output.data:type_name -> google.protobuf.Value + 141, // 126: aggregator.ManualTrigger.Config.data:type_name -> google.protobuf.Value + 103, // 127: aggregator.ManualTrigger.Config.headers:type_name -> aggregator.ManualTrigger.Config.HeadersEntry + 104, // 128: aggregator.ManualTrigger.Config.pathParams:type_name -> aggregator.ManualTrigger.Config.PathParamsEntry + 4, // 129: aggregator.ManualTrigger.Config.lang:type_name -> aggregator.Lang + 141, // 130: aggregator.ManualTrigger.Output.data:type_name -> google.protobuf.Value + 141, // 131: aggregator.ETHTransferNode.Output.data:type_name -> google.protobuf.Value + 141, // 132: aggregator.ContractWriteNode.Config.contract_abi:type_name -> google.protobuf.Value + 108, // 133: aggregator.ContractWriteNode.Config.method_calls:type_name -> aggregator.ContractWriteNode.MethodCall + 141, // 134: aggregator.ContractWriteNode.Output.data:type_name -> google.protobuf.Value + 141, // 135: aggregator.ContractWriteNode.MethodResult.method_abi:type_name -> google.protobuf.Value + 141, // 136: aggregator.ContractWriteNode.MethodResult.receipt:type_name -> google.protobuf.Value + 141, // 137: aggregator.ContractWriteNode.MethodResult.value:type_name -> google.protobuf.Value + 141, // 138: aggregator.ContractReadNode.Config.contract_abi:type_name -> google.protobuf.Value + 111, // 139: aggregator.ContractReadNode.Config.method_calls:type_name -> aggregator.ContractReadNode.MethodCall + 115, // 140: aggregator.ContractReadNode.MethodResult.data:type_name -> aggregator.ContractReadNode.MethodResult.StructuredField + 141, // 141: aggregator.ContractReadNode.Output.data:type_name -> google.protobuf.Value + 118, // 142: aggregator.GraphQLQueryNode.Config.variables:type_name -> aggregator.GraphQLQueryNode.Config.VariablesEntry + 141, // 143: aggregator.GraphQLQueryNode.Output.data:type_name -> google.protobuf.Value + 121, // 144: aggregator.RestAPINode.Config.headers:type_name -> aggregator.RestAPINode.Config.HeadersEntry + 141, // 145: aggregator.RestAPINode.Config.options:type_name -> google.protobuf.Value + 141, // 146: aggregator.RestAPINode.Output.data:type_name -> google.protobuf.Value + 4, // 147: aggregator.CustomCodeNode.Config.lang:type_name -> aggregator.Lang + 141, // 148: aggregator.CustomCodeNode.Output.data:type_name -> google.protobuf.Value + 141, // 149: aggregator.BalanceNode.Output.data:type_name -> google.protobuf.Value + 126, // 150: aggregator.BranchNode.Config.conditions:type_name -> aggregator.BranchNode.Condition + 141, // 151: aggregator.BranchNode.Output.data:type_name -> google.protobuf.Value + 141, // 152: aggregator.FilterNode.Output.data:type_name -> google.protobuf.Value + 3, // 153: aggregator.LoopNode.Config.execution_mode:type_name -> aggregator.ExecutionMode + 141, // 154: aggregator.LoopNode.Output.data:type_name -> google.protobuf.Value + 5, // 155: aggregator.Execution.Step.error_code:type_name -> aggregator.ErrorCode + 141, // 156: aggregator.Execution.Step.config:type_name -> google.protobuf.Value + 141, // 157: aggregator.Execution.Step.metadata:type_name -> google.protobuf.Value + 141, // 158: aggregator.Execution.Step.execution_context:type_name -> google.protobuf.Value + 96, // 159: aggregator.Execution.Step.block_trigger:type_name -> aggregator.BlockTrigger.Output + 92, // 160: aggregator.Execution.Step.fixed_time_trigger:type_name -> aggregator.FixedTimeTrigger.Output + 94, // 161: aggregator.Execution.Step.cron_trigger:type_name -> aggregator.CronTrigger.Output + 100, // 162: aggregator.Execution.Step.event_trigger:type_name -> aggregator.EventTrigger.Output + 102, // 163: aggregator.Execution.Step.manual_trigger:type_name -> aggregator.ManualTrigger.Output + 106, // 164: aggregator.Execution.Step.eth_transfer:type_name -> aggregator.ETHTransferNode.Output + 117, // 165: aggregator.Execution.Step.graphql:type_name -> aggregator.GraphQLQueryNode.Output + 114, // 166: aggregator.Execution.Step.contract_read:type_name -> aggregator.ContractReadNode.Output + 109, // 167: aggregator.Execution.Step.contract_write:type_name -> aggregator.ContractWriteNode.Output + 123, // 168: aggregator.Execution.Step.custom_code:type_name -> aggregator.CustomCodeNode.Output + 120, // 169: aggregator.Execution.Step.rest_api:type_name -> aggregator.RestAPINode.Output + 128, // 170: aggregator.Execution.Step.branch:type_name -> aggregator.BranchNode.Output + 130, // 171: aggregator.Execution.Step.filter:type_name -> aggregator.FilterNode.Output + 132, // 172: aggregator.Execution.Step.loop:type_name -> aggregator.LoopNode.Output + 125, // 173: aggregator.Execution.Step.balance:type_name -> aggregator.BalanceNode.Output + 141, // 174: aggregator.Task.InputVariablesEntry.value:type_name -> google.protobuf.Value + 141, // 175: aggregator.CreateTaskReq.InputVariablesEntry.value:type_name -> google.protobuf.Value + 141, // 176: aggregator.TriggerTaskReq.TriggerInputEntry.value:type_name -> google.protobuf.Value + 141, // 177: aggregator.RunNodeWithInputsReq.InputVariablesEntry.value:type_name -> google.protobuf.Value + 141, // 178: aggregator.RunTriggerReq.TriggerInputEntry.value:type_name -> google.protobuf.Value + 141, // 179: aggregator.SimulateTaskReq.InputVariablesEntry.value:type_name -> google.protobuf.Value + 141, // 180: aggregator.EstimateFeesReq.InputVariablesEntry.value:type_name -> google.protobuf.Value + 45, // 181: aggregator.Aggregator.GetKey:input_type -> aggregator.GetKeyReq + 61, // 182: aggregator.Aggregator.GetSignatureFormat:input_type -> aggregator.GetSignatureFormatReq + 34, // 183: aggregator.Aggregator.GetNonce:input_type -> aggregator.NonceRequest + 47, // 184: aggregator.Aggregator.GetWallet:input_type -> aggregator.GetWalletReq + 49, // 185: aggregator.Aggregator.SetWallet:input_type -> aggregator.SetWalletReq + 36, // 186: aggregator.Aggregator.ListWallets:input_type -> aggregator.ListWalletReq + 50, // 187: aggregator.Aggregator.WithdrawFunds:input_type -> aggregator.WithdrawFundsReq + 32, // 188: aggregator.Aggregator.CreateTask:input_type -> aggregator.CreateTaskReq + 39, // 189: aggregator.Aggregator.ListTasks:input_type -> aggregator.ListTasksReq + 11, // 190: aggregator.Aggregator.GetTask:input_type -> aggregator.IdReq + 41, // 191: aggregator.Aggregator.ListExecutions:input_type -> aggregator.ListExecutionsReq + 43, // 192: aggregator.Aggregator.GetExecution:input_type -> aggregator.ExecutionReq + 43, // 193: aggregator.Aggregator.GetExecutionStatus:input_type -> aggregator.ExecutionReq + 66, // 194: aggregator.Aggregator.SetTaskEnabled:input_type -> aggregator.SetTaskEnabledReq + 11, // 195: aggregator.Aggregator.DeleteTask:input_type -> aggregator.IdReq + 52, // 196: aggregator.Aggregator.TriggerTask:input_type -> aggregator.TriggerTaskReq + 54, // 197: aggregator.Aggregator.CreateSecret:input_type -> aggregator.CreateOrUpdateSecretReq + 59, // 198: aggregator.Aggregator.DeleteSecret:input_type -> aggregator.DeleteSecretReq + 55, // 199: aggregator.Aggregator.ListSecrets:input_type -> aggregator.ListSecretsReq + 54, // 200: aggregator.Aggregator.UpdateSecret:input_type -> aggregator.CreateOrUpdateSecretReq + 68, // 201: aggregator.Aggregator.GetWorkflowCount:input_type -> aggregator.GetWorkflowCountReq + 70, // 202: aggregator.Aggregator.GetExecutionCount:input_type -> aggregator.GetExecutionCountReq + 72, // 203: aggregator.Aggregator.GetExecutionStats:input_type -> aggregator.GetExecutionStatsReq + 74, // 204: aggregator.Aggregator.RunNodeWithInputs:input_type -> aggregator.RunNodeWithInputsReq + 76, // 205: aggregator.Aggregator.RunTrigger:input_type -> aggregator.RunTriggerReq + 78, // 206: aggregator.Aggregator.SimulateTask:input_type -> aggregator.SimulateTaskReq + 9, // 207: aggregator.Aggregator.GetTokenMetadata:input_type -> aggregator.GetTokenMetadataReq + 79, // 208: aggregator.Aggregator.EstimateFees:input_type -> aggregator.EstimateFeesReq + 46, // 209: aggregator.Aggregator.GetKey:output_type -> aggregator.KeyResp + 62, // 210: aggregator.Aggregator.GetSignatureFormat:output_type -> aggregator.GetSignatureFormatResp + 35, // 211: aggregator.Aggregator.GetNonce:output_type -> aggregator.NonceResp + 48, // 212: aggregator.Aggregator.GetWallet:output_type -> aggregator.GetWalletResp + 48, // 213: aggregator.Aggregator.SetWallet:output_type -> aggregator.GetWalletResp + 38, // 214: aggregator.Aggregator.ListWallets:output_type -> aggregator.ListWalletResp + 51, // 215: aggregator.Aggregator.WithdrawFunds:output_type -> aggregator.WithdrawFundsResp + 33, // 216: aggregator.Aggregator.CreateTask:output_type -> aggregator.CreateTaskResp + 40, // 217: aggregator.Aggregator.ListTasks:output_type -> aggregator.ListTasksResp + 31, // 218: aggregator.Aggregator.GetTask:output_type -> aggregator.Task + 42, // 219: aggregator.Aggregator.ListExecutions:output_type -> aggregator.ListExecutionsResp + 30, // 220: aggregator.Aggregator.GetExecution:output_type -> aggregator.Execution + 44, // 221: aggregator.Aggregator.GetExecutionStatus:output_type -> aggregator.ExecutionStatusResp + 67, // 222: aggregator.Aggregator.SetTaskEnabled:output_type -> aggregator.SetTaskEnabledResp + 65, // 223: aggregator.Aggregator.DeleteTask:output_type -> aggregator.DeleteTaskResp + 53, // 224: aggregator.Aggregator.TriggerTask:output_type -> aggregator.TriggerTaskResp + 63, // 225: aggregator.Aggregator.CreateSecret:output_type -> aggregator.CreateSecretResp + 60, // 226: aggregator.Aggregator.DeleteSecret:output_type -> aggregator.DeleteSecretResp + 58, // 227: aggregator.Aggregator.ListSecrets:output_type -> aggregator.ListSecretsResp + 64, // 228: aggregator.Aggregator.UpdateSecret:output_type -> aggregator.UpdateSecretResp + 69, // 229: aggregator.Aggregator.GetWorkflowCount:output_type -> aggregator.GetWorkflowCountResp + 71, // 230: aggregator.Aggregator.GetExecutionCount:output_type -> aggregator.GetExecutionCountResp + 73, // 231: aggregator.Aggregator.GetExecutionStats:output_type -> aggregator.GetExecutionStatsResp + 75, // 232: aggregator.Aggregator.RunNodeWithInputs:output_type -> aggregator.RunNodeWithInputsResp + 77, // 233: aggregator.Aggregator.RunTrigger:output_type -> aggregator.RunTriggerResp + 30, // 234: aggregator.Aggregator.SimulateTask:output_type -> aggregator.Execution + 10, // 235: aggregator.Aggregator.GetTokenMetadata:output_type -> aggregator.GetTokenMetadataResp + 89, // 236: aggregator.Aggregator.EstimateFees:output_type -> aggregator.EstimateFeesResp 209, // [209:237] is the sub-list for method output_type 181, // [181:209] is the sub-list for method input_type 181, // [181:181] is the sub-list for extension type_name @@ -10605,15 +10790,15 @@ func file_avs_proto_init() { (*RunTriggerResp_EventTrigger)(nil), (*RunTriggerResp_ManualTrigger)(nil), } - file_avs_proto_msgTypes[86].OneofWrappers = []any{} - file_avs_proto_msgTypes[87].OneofWrappers = []any{} - file_avs_proto_msgTypes[88].OneofWrappers = []any{} - file_avs_proto_msgTypes[96].OneofWrappers = []any{} - file_avs_proto_msgTypes[97].OneofWrappers = []any{} + file_avs_proto_msgTypes[89].OneofWrappers = []any{} + file_avs_proto_msgTypes[90].OneofWrappers = []any{} + file_avs_proto_msgTypes[91].OneofWrappers = []any{} file_avs_proto_msgTypes[99].OneofWrappers = []any{} file_avs_proto_msgTypes[100].OneofWrappers = []any{} - file_avs_proto_msgTypes[108].OneofWrappers = []any{} - file_avs_proto_msgTypes[122].OneofWrappers = []any{ + file_avs_proto_msgTypes[102].OneofWrappers = []any{} + file_avs_proto_msgTypes[103].OneofWrappers = []any{} + file_avs_proto_msgTypes[111].OneofWrappers = []any{} + file_avs_proto_msgTypes[125].OneofWrappers = []any{ (*Execution_Step_BlockTrigger)(nil), (*Execution_Step_FixedTimeTrigger)(nil), (*Execution_Step_CronTrigger)(nil), @@ -10635,8 +10820,8 @@ func file_avs_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_avs_proto_rawDesc), len(file_avs_proto_rawDesc)), - NumEnums: 7, - NumMessages: 130, + NumEnums: 8, + NumMessages: 133, NumExtensions: 0, NumServices: 1, }, diff --git a/protobuf/avs.proto b/protobuf/avs.proto index ede378b5..0747adec 100644 --- a/protobuf/avs.proto +++ b/protobuf/avs.proto @@ -36,6 +36,16 @@ enum NodeType { NODE_TYPE_BALANCE = 10; // Balance node for retrieving wallet token balances } +// ExecutionTier defines value-capture pricing groups for on-chain execution nodes. +// Tiers are pure pricing buckets — meaning comes from classification logic, not the label. +// Non-execution nodes use UNSPECIFIED (no fee). +enum ExecutionTier { + EXECUTION_TIER_UNSPECIFIED = 0; // No value-capture fee (non-execution nodes) + EXECUTION_TIER_1 = 1; // Pricing group 1 (default: 0.03% of tx value) + EXECUTION_TIER_2 = 2; // Pricing group 2 (default: 0.09% of tx value) + EXECUTION_TIER_3 = 3; // Pricing group 3 (default: 0.18% of tx value) +} + enum ExecutionMode { EXECUTION_MODE_SEQUENTIAL = 0; // Run iterations sequentially (default for safety) EXECUTION_MODE_PARALLEL = 1; // Run iterations in parallel @@ -688,17 +698,10 @@ message Execution { // This helps clients understand execution order without calculating based on timestamps int64 index = 6; - // Total gas cost for the entire workflow execution (sum of all blockchain operations) - // Units are in wei. Use string for large numbers to avoid overflow. - // - // Empty string means gas data was not computed (e.g., workflow has no on-chain steps, - // or receipt was unavailable). Clients should treat both "" and "0" as "no data" - // since real on-chain transactions always cost gas. - string total_gas_cost = 7; - - // Automation fee charged for monitoring and executing this workflow. - // Currently hard-coded to zero; will be populated when automation fees are enabled. - FeeAmount automation_fee = 9; + // Fees actually charged for this execution (matches EstimateFeesResp format) + Fee execution_fee = 7; // Flat platform fee charged {amount, unit: "USD"} + repeated NodeCOGS cogs = 9; // Per-node actual gas/API costs {fee: {amount, unit: "WEI"}} + ValueFee value_fee = 10; // Value-capture fee charged (post-paid) {fee: {amount, unit: "PERCENTAGE"}} message Step { string id = 1; @@ -1385,58 +1388,74 @@ message SmartWalletCreationFee { string wallet_address = 4; // Predicted or existing wallet address } -// Automation fee structure based on trigger type and duration -message AutomationFee { - FeeAmount base_fee = 1; // Base automation fee - FeeAmount monitoring_fee = 2; // Ongoing monitoring cost (for time/event triggers) - FeeAmount execution_fee = 3; // Per-execution fee - - // Fee calculation details - string trigger_type = 4; // "manual", "cron", "event", "block", "fixed_time" - int64 estimated_executions = 5; // Estimated number of executions over workflow lifetime - int64 duration_minutes = 6; // How long monitoring will run (minutes) - string fee_calculation_method = 7; // Description of how fee was calculated +// Unit-safe fee value. Every monetary field is self-describing. +// Units: "USD" (fiat), "WEI" (native token smallest unit), "PERCENTAGE" (0.03 = 0.03%) +message Fee { + string amount = 1; // Numeric value as string (precision-safe) + string unit = 2; // "USD", "WEI", "PERCENTAGE" } -// Promotional discounts and fee reductions +// Native token metadata for the chain +message NativeToken { + string symbol = 1; // e.g., "ETH" + int32 decimals = 2; // e.g., 18 +} + +// Per-node cost of goods sold (gas, external API costs, etc.) +message NodeCOGS { + string node_id = 1; + string cost_type = 2; // "gas", "external_api", "wallet_creation" + Fee fee = 3; // Cost in WEI + string gas_units = 4; // Gas units (for gas costs only) +} + +// Workflow-level value-capture fee. +// Single fee for the entire workflow based on what it does (not per-node). +message ValueFee { + Fee fee = 1; // { amount: "0.03", unit: "PERCENTAGE" } + ExecutionTier tier = 2; // Pricing group (TIER_1, TIER_2, TIER_3) + string value_base = 3; // What the percentage applies to (e.g., "input_token_value") + string classification_method = 4; // "rule_based" (V1) or "llm" (V2) + float confidence = 5; // Classification confidence (0.0–1.0) + string reason = 6; // Why this tier was assigned +} + +// Promotional discount message FeeDiscount { - string discount_type = 1; // "new_user", "volume", "promotional", "beta_program" - string discount_name = 2; // Human-readable discount name - string applies_to = 3; // "gas_fees", "automation_fees", "creation_fees", "all" - float discount_percentage = 4; // Discount percentage (0.0 to 100.0) - FeeAmount discount_amount = 5; // Absolute discount amount - string expiry_date = 6; // When discount expires (ISO 8601 format) - string terms = 7; // Terms and conditions for discount + string discount_type = 1; // "new_user", "volume", "promotional", "beta_program" + string discount_name = 2; + Fee discount = 3; // Discount amount or percentage + string expiry_date = 4; + string terms = 5; } // Response message for EstimateFees +// All fees are per-execution. No totals — client computes. +// Components: execution_fee (USD) + cogs[] (WEI) + value_fee (PERCENTAGE) message EstimateFeesResp { - bool success = 1; // Whether fee estimation was successful - string error = 2; // Error message if estimation failed - ErrorCode error_code = 3; // Structured error code - - // Fee breakdown - GasFeeBreakdown gas_fees = 4; // Estimated gas fees - AutomationFee automation_fees = 5; // Automation and monitoring fees - SmartWalletCreationFee creation_fees = 6; // Smart wallet creation fees (if needed) - - // Total fees - FeeAmount total_fees = 7; // Sum of all fees - - // Discounts and promotions - repeated FeeDiscount discounts = 8; // Applied discounts - FeeAmount total_discounts = 9; // Total discount amount - FeeAmount final_total = 10; // Final total after discounts - - // Estimation metadata - int64 estimated_at = 11; // Timestamp when estimation was performed - string chain_id = 12; // Blockchain chain ID - string price_data_source = 13; // Source of price data ("coingecko", "chainlink", "cached") - int64 price_data_age_seconds = 14; // Age of price data in seconds - - // Warnings and recommendations - repeated string warnings = 15; // Warnings about fee estimation - repeated string recommendations = 16; // Recommendations for cost optimization + bool success = 1; + string error = 2; + ErrorCode error_code = 3; + + // Chain and token context + string chain_id = 4; + NativeToken native_token = 5; + + // Flat per-execution platform fee + Fee execution_fee = 6; + + // Cost of goods sold — per-node operational costs (gas, external API) + repeated NodeCOGS cogs = 7; + + // Workflow-level value-capture fee (single, not per-node) + ValueFee value_fee = 8; + + // Discounts (client sums if needed) + repeated FeeDiscount discounts = 9; + + // Pricing metadata + string pricing_model = 10; // "v1" + repeated string warnings = 11; } // EventCondition represents a condition to evaluate on decoded event data