Skip to content

feat: value-capture fee estimation with tiered pricing#503

Merged
chrisli30 merged 8 commits into
stagingfrom
feat/node-tier-pricing
Apr 6, 2026
Merged

feat: value-capture fee estimation with tiered pricing#503
chrisli30 merged 8 commits into
stagingfrom
feat/node-tier-pricing

Conversation

@chrisli30

Copy link
Copy Markdown
Member

Summary

  • Replace trigger-based monitoring/execution fee system with a three-component fee model: execution_fee (flat per-run) + cogs[] (per-node gas costs) + value_fee (workflow-level % of tx value)
  • Tiers are pure pricing groups (tier_1/2/3) classified by urgency/importance, not named categories
  • Hard costs (execution_fee + COGS) enforced atomically in UserOp; value_fee is post-paid
  • All fees settled in native token (ETH); USD is display-only
  • Add docs/ARCHITECTURE.md (full system architecture) and docs/FEE_ESTIMATION.md (fee model, billing, settlement design)

Fee structure

execution_fee  ($0.02 flat)     — packaged in UserOp, atomic
cogs[]         (gas per node)   — packaged in UserOp, atomic
value_fee      (tier % of tx)   — post-paid after execution
Tier Default % Classification
Tier 1 0.03% Simple execution
Tier 2 0.09% Optimization/convenience
Tier 3 0.18% Risk/urgency, must-execute

V1: all on-chain nodes default to Tier 1. V2: LLM-based workflow classification.

Files changed

  • protobuf/avs.proto — new ExecutionTier enum, NodeCOGS, ValueFee messages, flat EstimateFeesResp
  • core/taskengine/fee_estimator.goestimateCOGS(), classifyWorkflowValue(), removed old monitoring/trigger-based logic
  • core/config/config.goFeeRatesConfig with ExecutionFeeUSD + tier percentages
  • core/taskengine/fee_estimator_test.go — 10 tests (20 subtests) covering COGS, value classification, config, execution count
  • docs/ARCHITECTURE.md — new: full system architecture doc
  • docs/FEE_ESTIMATION.md — new: fee model, billing & settlement design

Test plan

  • go build ./core/... ./aggregator/... ./protobuf/... passes
  • go test ./core/taskengine/... -run "TestFeeEstimator|TestIsOnChain|TestDefaultFee|TestConvertFeeRates|TestClassifyWorkflow|TestEstimateCOGS|TestEstimateExecution|TestCustomConfig" — all 10 tests pass
  • Pre-existing UniswapSwap test failures confirmed on staging (unrelated)
  • Integration test with actual EstimateFees RPC endpoint

🤖 Generated with Claude Code

Chris Li added 2 commits April 4, 2026 13:00
Replace the trigger-based monitoring/execution fee system with a
three-component fee model:

- execution_fee: flat per-run platform fee ($0.02), packaged in UserOp
- cogs[]: per-node operational costs (gas for on-chain nodes), atomic
- value_fee: workflow-level value-capture % of tx value, post-paid

Key design decisions:
- Tiers are pure pricing groups (tier_1/2/3), not named categories
- Classification by urgency: failure=loss → Tier 3, improves outcome
  → Tier 2, simple → Tier 1. V1 defaults all to Tier 1.
- Non-execution nodes (logic, reads, API calls) have no fees
- Hard costs (execution_fee + COGS) enforced atomically in UserOp;
  value_fee is post-paid — user experiences value first
- All fees settled in native token (ETH), USD is display-only
- No account balance system — blockchain enforces solvency

Also adds:
- docs/ARCHITECTURE.md — full system architecture doc
- docs/FEE_ESTIMATION.md — fee model, billing, and settlement design

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the fee estimation model to a tiered value-capture design, replacing the prior trigger/duration-based automation fee approach. It introduces new protobuf response shapes and accompanying docs to describe pricing, billing, and settlement.

Changes:

  • Replaced trigger-based monitoring/execution fees with execution_fee + per-node cogs[] + workflow-level value_fee (tiered %).
  • Updated protobuf schema (ExecutionTier, NodeCOGS, ValueFee) and flattened EstimateFeesResp to match the new fee model.
  • Added/updated documentation and example YAML configuration for the new pricing model, plus unit tests for estimator behavior.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
README.md Repoints fee documentation to the new fee estimation doc.
protobuf/avs.proto Adds tier/value-fee messages and restructures EstimateFeesResp.
protobuf/avs.pb.go Regenerated protobuf Go bindings reflecting schema changes.
core/taskengine/fee_estimator.go Implements new estimator flow (execution fee, COGS, value tier classification).
core/taskengine/fee_estimator_test.go Adds tests for tier classification, COGS, config conversion, execution counts.
core/config/config.go Replaces old fee-rate config with execution fee + tier % config and YAML loading.
config/aggregator.example.yaml Updates example config to new fee structure and tier settings.
aggregator/rpc_server.go Updates logging to match new EstimateFeesResp fields.
docs/FEE_ESTIMATION.md New: documents the new fee model, configuration, and settlement logic.
docs/ARCHITECTURE.md New: system architecture doc including fee model summary.
docs/API_PROTOCOL_COMPARISON.md New: protocol comparison doc for partner-facing API design.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread core/config/config.go Outdated
Comment on lines 538 to 559
// loadFeeRatesFromConfig loads fee config from YAML with fallback to defaults
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
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),
}

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadFeeRatesFromConfig treats 0.0 as “unset” (if configValue != 0.0), which makes it impossible to intentionally configure zero fees (e.g., beta/free tiers or execution_fee_usd: 0.0). This contradicts the example configs/docs. Consider using pointer fields (e.g., *float64) in ConfigRaw or decoding via yaml.Node so you can distinguish “missing” from an explicit zero.

Copilot uses AI. Check for mistakes.
Comment thread protobuf/avs.proto Outdated
Comment on lines +1440 to +1451
// Flat per-execution platform fee (charged every time the workflow runs)
FeeAmount execution_fee = 4;

// Cost of goods sold — per-node operational costs (gas, external API costs)
repeated NodeCOGS cogs = 5;

// Workflow-level value-capture fee (single, not per-node)
ValueFee value_fee = 6;

// Smart wallet creation (one-time, if needed)
SmartWalletCreationFee creation_fees = 8;

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EstimateFeesResp reuses existing field numbers (e.g., 4/5/6) for completely different types/semantics (previously gas_fees, automation_fees, creation_fees). This will break backward compatibility for any existing protobuf clients (they’ll decode these fields into the old message types, typically as empty/zero values). To avoid silent client breakage, keep existing field numbers/types and add new fields with new numbers (or introduce a new RPC/message version) and reserve the old field numbers.

Suggested change
// Flat per-execution platform fee (charged every time the workflow runs)
FeeAmount execution_fee = 4;
// Cost of goods sold — per-node operational costs (gas, external API costs)
repeated NodeCOGS cogs = 5;
// Workflow-level value-capture fee (single, not per-node)
ValueFee value_fee = 6;
// Smart wallet creation (one-time, if needed)
SmartWalletCreationFee creation_fees = 8;
// Legacy fields kept on their original tag numbers for wire compatibility.
// New clients should prefer the pricing-model fields below.
FeeAmount gas_fees = 4;
FeeAmount automation_fees = 5;
SmartWalletCreationFee creation_fees = 6;
// Flat per-execution platform fee (charged every time the workflow runs)
FeeAmount execution_fee = 21;
// Cost of goods sold — per-node operational costs (gas, external API costs)
repeated NodeCOGS cogs = 22;
// Workflow-level value-capture fee (single, not per-node)
ValueFee value_fee = 23;

Copilot uses AI. Check for mistakes.
Comment thread protobuf/avs.proto Outdated
Comment on lines +1446 to +1456
// Workflow-level value-capture fee (single, not per-node)
ValueFee value_fee = 6;

// Smart wallet creation (one-time, if needed)
SmartWalletCreationFee creation_fees = 8;

// Totals
FeeAmount total_fees = 9; // Sum of execution_fee + total_cogs + value_fee
repeated FeeDiscount discounts = 10;
FeeAmount total_discounts = 11;
FeeAmount final_total = 12; // After discounts

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment on total_fees says it’s the sum of execution_fee + total_cogs + value_fee, but the implementation computes totals from execution_fee + cogs + creation_fees and explicitly treats value_fee as post-paid (% at execution time). Please align the proto comment/field meaning with actual behavior (and clarify whether creation_fees is included).

Suggested change
// Workflow-level value-capture fee (single, not per-node)
ValueFee value_fee = 6;
// Smart wallet creation (one-time, if needed)
SmartWalletCreationFee creation_fees = 8;
// Totals
FeeAmount total_fees = 9; // Sum of execution_fee + total_cogs + value_fee
repeated FeeDiscount discounts = 10;
FeeAmount total_discounts = 11;
FeeAmount final_total = 12; // After discounts
// Workflow-level value-capture fee (single, not per-node; post-paid as a % at execution time)
ValueFee value_fee = 6;
// Smart wallet creation fee (one-time, if needed; included in totals below when applicable)
SmartWalletCreationFee creation_fees = 8;
// Totals for upfront estimated charges only (excludes post-paid value_fee)
FeeAmount total_fees = 9; // Sum of execution_fee + total_cogs + creation_fees
repeated FeeDiscount discounts = 10;
FeeAmount total_discounts = 11;
FeeAmount final_total = 12; // total_fees after discounts; still excludes value_fee

Copilot uses AI. Check for mistakes.
Comment thread docs/FEE_ESTIMATION.md Outdated
Comment on lines +82 to +89
**Beta (free execution):**
```yaml
fee_rates:
tiers:
tier_1: 0.0
tier_2: 0.0
tier_3: 0.0
```

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs show configuring tiers to 0.0 for a “Beta (free execution)” mode, but the current YAML parsing in loadFeeRatesFromConfig treats 0.0 as “unset” and will fall back to defaults. Either adjust parsing to distinguish “missing” vs explicit zero, or update this section to reflect the actual behavior.

Copilot uses AI. Check for mistakes.
Comment thread docs/FEE_ESTIMATION.md Outdated
Comment on lines +54 to +61
### Gas fees

Gas costs are estimated per on-chain node via `estimateGasFees()`. This covers the blockchain execution cost (EntryPoint, bundler, smart wallet operations). Gas estimation is independent of the value-capture tier.

Nodes that incur gas:
- `contract_write` — 150,000 gas estimate (conservative)
- `eth_transfer` — 50,000 gas estimate (smart wallet transfer)
- `loop` — 300,000 gas estimate (may contain contract writes)

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “Gas fees” section references estimateGasFees(), but the implementation now uses estimateCOGS() and no longer returns a GasFeeBreakdown. Updating the function name and returned structure here will prevent readers from looking for APIs that no longer exist.

Copilot uses AI. Check for mistakes.
Comment thread docs/FEE_ESTIMATION.md Outdated
Comment on lines +164 to +178
### Response structure

`EstimateFeesResp` (flat, not nested):
- `execution_fee` — flat per-run platform fee
- `cogs[]` — per-node operational costs (gas, future: API costs)
- `value_fee` — single workflow-level object: tier, percentage, classification method, confidence, reason
- `total_fees` — sum of execution_fee + COGS (value_fee is % at execution time, not included)
- `estimated_executions` — how many times the workflow will fire
- `pricing_model` — `"v1"`

### Total workflow fee formula

```
Total per execution = execution_fee + Σ(cogs) + (tier_percentage × tx_value)
|____________atomic_____________| |___post-paid___|

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

total_fees is described as execution_fee + COGS (and the formula is “per execution”), but the implementation also includes one-time creation_fees in total_fees when wallet creation is required. Please clarify whether total_fees includes creation_fees (and distinguish one-time vs per-execution totals in the response structure and formula).

Copilot uses AI. Check for mistakes.
Comment thread docs/ARCHITECTURE.md Outdated
Comment on lines +218 to +220
See [docs/FEE_ESTIMATION.md](FEE_ESTIMATION.md) for full details.

Total workflow fee = gas costs + sum of value-capture fees on executed on-chain nodes.

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fee estimation docs mention estimateGasFees() and the final formula omits the new execution_fee flat fee. Since the code now models execution_fee + COGS + value_fee (and may include creation_fees), please update the “Total workflow fee” statement and referenced function name to match the new fee model.

Suggested change
See [docs/FEE_ESTIMATION.md](FEE_ESTIMATION.md) for full details.
Total workflow fee = gas costs + sum of value-capture fees on executed on-chain nodes.
See [docs/FEE_ESTIMATION.md](FEE_ESTIMATION.md) for full details on workflow fee estimation.
Total workflow fee = execution_fee + COGS + sum of value-capture fees on executed on-chain nodes, plus any applicable creation_fees.

Copilot uses AI. Check for mistakes.
Comment thread core/taskengine/fee_estimator.go Outdated
Comment on lines +228 to +229
Discounts: nil, // TODO: re-implement discounts for new structure
TotalDiscounts: nil,

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EstimateFees returns Discounts and TotalDiscounts as nil while still populating FinalTotal. This can be a footgun for clients that assume these are always set and directly dereference them. Consider returning an explicit zero FeeAmount for total_discounts (and an empty slice for discounts) until discounts are re-implemented.

Suggested change
Discounts: nil, // TODO: re-implement discounts for new structure
TotalDiscounts: nil,
Discounts: []*avsproto.Discount{}, // TODO: re-implement discounts for new structure
TotalDiscounts: &avsproto.FeeAmount{},

Copilot uses AI. Check for mistakes.
- Use pointer fields in YAML config parsing to distinguish "missing"
  (nil → use default) from explicit zero (0.0 → free tier)
- Return empty slice/zero FeeAmount for discounts instead of nil
- Fix proto comments: total_fees excludes post-paid value_fee
- Fix stale function references in docs (estimateGasFees → estimateCOGS)
- Clarify total_fees includes creation_fees in docs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread core/taskengine/fee_estimator.go Outdated
CreationRequired: false,
WalletAddress: runnerAddress.Hex(),
}, nil
return runnerAddress, false, nil, nil

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If CodeAt fails, this returns (walletCreationNeeded=false, walletCreationGasWei=nil, err=nil), which can silently omit wallet-creation COGS and under-estimate fees while hiding an RPC failure. Consider returning a non-nil error, or falling back to a conservative wallet-creation estimate and adding a warning so clients can treat the estimate as degraded.

Suggested change
return runnerAddress, false, nil, nil
return runnerAddress, false, nil, fmt.Errorf("failed to check smart wallet deployment status for %s: %w", runnerAddress.Hex(), err)

Copilot uses AI. Check for mistakes.
Comment thread docs/FEE_ESTIMATION.md Outdated
Comment on lines +101 to +115
All fees are denominated in **native token (ETH)**, not USD. USD amounts in the API response are display-only. Settlement uses ETH price at execution time.

### Enforcement split

| Component | Enforcement | Rationale |
|-----------|-------------|-----------|
| `execution_fee` | **Atomic in UserOp** — included in the transaction | Operational cost — if wallet can't cover it, UserOp reverts on-chain |
| `cogs` (gas, API) | **Atomic in UserOp** — included in the transaction | Real cost — blockchain rejects if insufficient balance |
| `value_fee` | **Post-paid** — tracked off-chain after execution | Value-capture revenue — user experiences value first, pays after |

No account balance system or prepaid deposits. The blockchain is the enforcement layer for hard costs — if the user's smart wallet doesn't have enough ETH, the UserOp reverts automatically.

### How atomic fees work

The `execution_fee` and `cogs` are packaged into the UserOp alongside the workflow's contract calls. The smart wallet must have enough ETH to cover all of it. If not, the entire transaction is rejected by the blockchain — no execution happens, no cost to Ava.

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doc says all fees are denominated in native token and USD is display-only, but the API now returns execution_fee explicitly as unit "USD" (and cogs as "WEI"). Please update the wording to match the actual API contract (or update the API to also provide an ETH/WEI-denominated execution_fee for on-chain enforcement).

Suggested change
All fees are denominated in **native token (ETH)**, not USD. USD amounts in the API response are display-only. Settlement uses ETH price at execution time.
### Enforcement split
| Component | Enforcement | Rationale |
|-----------|-------------|-----------|
| `execution_fee` | **Atomic in UserOp**included in the transaction | Operational cost — if wallet can't cover it, UserOp reverts on-chain |
| `cogs` (gas, API) | **Atomic in UserOp** — included in the transaction | Real cost blockchain rejects if insufficient balance |
| `value_fee` | **Post-paid** — tracked off-chain after execution | Value-capture revenue — user experiences value first, pays after |
No account balance system or prepaid deposits. The blockchain is the enforcement layer for hard costs — if the user's smart wallet doesn't have enough ETH, the UserOp reverts automatically.
### How atomic fees work
The `execution_fee` and `cogs` are packaged into the UserOp alongside the workflow's contract calls. The smart wallet must have enough ETH to cover all of it. If not, the entire transaction is rejected by the blockchain — no execution happens, no cost to Ava.
The API currently returns fee components in mixed units: `execution_fee` is quoted in **USD**, while `cogs` is quoted in **WEI**. This means USD values are part of the API contract for quoting, but only native-token-denominated amounts can be enforced directly on-chain without an additional conversion step.
### Enforcement split
| Component | Enforcement | Rationale |
|-----------|-------------|-----------|
| `execution_fee` | **Quoted off-chain**returned by the API in USD; must be converted to ETH/WEI before any on-chain enforcement | Operational pricing is exposed as a fiat quote in the current API contract |
| `cogs` (gas, API) | **Atomic in UserOp**native-token cost included in the transaction | Real cost is returned in `WEI`, so blockchain enforcement is possible if insufficient balance |
| `value_fee` | **Post-paid** — tracked off-chain after execution | Value-capture revenue — user experiences value first, pays after |
No account balance system or prepaid deposits. The blockchain is the enforcement layer for native-token-denominated hard costs — if the user's smart wallet doesn't have enough ETH/WEI to cover those amounts, the UserOp reverts automatically.
### How atomic fees work
In the current API contract, `cogs` is the directly atomic component because it is returned in `WEI`. `execution_fee` is returned in `USD`, so it is a quote unless and until it is converted into a native-token amount before submission alongside the workflow's contract calls. The smart wallet must have enough ETH to cover all native-token-denominated charges. If not, the entire transaction is rejected by the blockchain — no execution happens, no cost to Ava.

Copilot uses AI. Check for mistakes.
Comment thread docs/FEE_ESTIMATION.md Outdated
Comment on lines +166 to +172
`EstimateFeesResp` (flat, not nested):
- `execution_fee` — flat per-run platform fee
- `cogs[]` — per-node operational costs (gas, future: API costs)
- `value_fee` — single workflow-level object: tier, percentage, classification method, confidence, reason
- `total_fees` — sum of execution_fee + COGS + creation_fees (excludes post-paid value_fee)
- `estimated_executions` — how many times the workflow will fire
- `pricing_model` — `"v1"`

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The EstimateFeesResp field list here mentions total_fees and estimated_executions, but those fields were removed from the proto in this PR (EstimateFeesResp now only includes chain/token context + execution_fee + cogs + value_fee + discounts + pricing_model + warnings). Please update this section to avoid documenting fields that no longer exist.

Suggested change
`EstimateFeesResp` (flat, not nested):
- `execution_fee` — flat per-run platform fee
- `cogs[]` — per-node operational costs (gas, future: API costs)
- `value_fee` — single workflow-level object: tier, percentage, classification method, confidence, reason
- `total_fees` — sum of execution_fee + COGS + creation_fees (excludes post-paid value_fee)
- `estimated_executions` — how many times the workflow will fire
- `pricing_model``"v1"`
`EstimateFeesResp` (flat, not nested) includes:
- chain/token context fields
- `execution_fee` — flat per-run platform fee
- `cogs[]` — per-node operational costs (gas, future: API costs)
- `value_fee` — single workflow-level object: tier, percentage, classification method, confidence, reason
- `discounts` — any applied fee discounts
- `pricing_model``"v1"`
- `warnings` — non-fatal estimation notes or caveats

Copilot uses AI. Check for mistakes.
Comment thread docs/ARCHITECTURE.md Outdated
Fees have two independent components:

**1. Operational costs (estimated separately):**
- **Gas fees** — estimated per on-chain node (contract_write, eth_transfer, loop). Handled by `estimateGasFees()`.

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section still references estimateGasFees(), but the estimator implementation in this PR renamed/replaced that with estimateCOGS() returning NodeCOGS entries. Update the function name (and description if needed) so the architecture doc matches the code.

Suggested change
- **Gas fees** — estimated per on-chain node (contract_write, eth_transfer, loop). Handled by `estimateGasFees()`.
- **Gas fees** — estimated per on-chain node (contract_write, eth_transfer, loop). Handled by `estimateCOGS()`, which returns `NodeCOGS` entries.

Copilot uses AI. Check for mistakes.
Comment thread core/taskengine/executor.go Outdated
Comment on lines +565 to +570
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.ExecutionFee = &avsproto.Fee{Amount: "0", Unit: "USD"} // TODO: populate with actual execution fee
execution.Cogs = buildCOGSFromSteps(vm.ExecutionLogs) // Build COGS from step-level gas data
execution.ValueFee = &avsproto.ValueFee{Fee: &avsproto.Fee{Amount: "0", Unit: "PERCENTAGE"}} // TODO: populate with actual value fee

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Execution now documents these fields as "Fees actually charged", but this code always persists zeros for execution_fee/value_fee (with TODOs). That can mislead clients into thinking nothing was charged. Prefer leaving these fields nil until they can be populated correctly, or populate them from the same fee model used by EstimateFees (and/or execution-time settlement).

Suggested change
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.ExecutionFee = &avsproto.Fee{Amount: "0", Unit: "USD"} // TODO: populate with actual execution fee
execution.Cogs = buildCOGSFromSteps(vm.ExecutionLogs) // Build COGS from step-level gas data
execution.ValueFee = &avsproto.ValueFee{Fee: &avsproto.Fee{Amount: "0", Unit: "PERCENTAGE"}} // TODO: populate with actual value fee
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.ExecutionFee = nil // Leave unset until actual execution fee can be populated
execution.Cogs = buildCOGSFromSteps(vm.ExecutionLogs) // Build COGS from step-level gas data
execution.ValueFee = nil // Leave unset until actual value fee can be populated

Copilot uses AI. Check for mistakes.
Comment thread core/taskengine/engine.go Outdated
Comment on lines 2923 to 2927
Index: task.ExecutionCount, // Use current execution count for simulation (0-based)
ExecutionFee: &avsproto.Fee{Amount: "0", Unit: "USD"}, // TODO: populate with actual execution fee
Cogs: buildCOGSFromSteps(vm.ExecutionLogs), // Build COGS from step-level gas data
ValueFee: &avsproto.ValueFee{Fee: &avsproto.Fee{Amount: "0", Unit: "PERCENTAGE"}}, // TODO: populate with actual value fee
}

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simulation responses also set execution_fee/value_fee to zero unconditionally. Since these fields represent the fee model/amounts for the run, returning explicit zeros can be misinterpreted as "free" rather than "not computed". Consider omitting (nil) or populating them from the estimator to keep simulation output aligned with EstimateFees.

Copilot uses AI. Check for mistakes.
Comment thread core/taskengine/engine.go Outdated
Comment on lines +3271 to +3273
ExecutionFee: &avsproto.Fee{Amount: "0", Unit: "USD"},
Cogs: []*avsproto.NodeCOGS{},
ValueFee: &avsproto.ValueFee{Fee: &avsproto.Fee{Amount: "0", Unit: "PERCENTAGE"}},

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pending execution response now always includes zero-valued fee fields. As with other Execution responses, explicit zeros can be interpreted as "charged 0" rather than "unknown/not computed". Consider returning nil for these fee fields on pending executions until actual fees are available (or attach a warning/flag indicating they're placeholders).

Suggested change
ExecutionFee: &avsproto.Fee{Amount: "0", Unit: "USD"},
Cogs: []*avsproto.NodeCOGS{},
ValueFee: &avsproto.ValueFee{Fee: &avsproto.Fee{Amount: "0", Unit: "PERCENTAGE"}},
ExecutionFee: nil, // Unknown until execution completes
Cogs: []*avsproto.NodeCOGS{},
ValueFee: nil, // Unknown until execution completes

Copilot uses AI. Check for mistakes.
- Return error (not nil) when CodeAt fails in wallet creation check
- Use nil for execution_fee/value_fee in Execution when not yet computed
- Update docs: mixed-unit API contract, remove stale field references,
  fix function name (estimateGasFees → estimateCOGS)
- Add execution_fee_usd to config section
- Fix estimation flow (resolveRunnerAndWalletCreation, not old name)
- Document Fee/NativeToken/NodeCOGS/ValueFee proto messages
- Add 3 simulated EstimateFeesResp examples (alert-only, swap, liquidation)
- Document Execution response format (nil fees until billing implemented)
- Update ARCHITECTURE.md fee section to match
Execution responses now always include actual fee values:
- execution_fee: populated from config (known upfront, even for pending)
- value_fee: classified from step composition after execution
  (nil only for pending executions where steps are unknown)
- cogs: already populated from step-level gas receipts

Add buildExecutionFee() and buildValueFee() helpers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants