Skip to content

Make EVM destination funding fee-aware - #1312

Merged
ebma merged 12 commits into
stagingfrom
codex/dynamic-evm-destination-funding
Aug 10, 2026
Merged

Make EVM destination funding fee-aware#1312
ebma merged 12 commits into
stagingfrom
codex/dynamic-evm-destination-funding

Conversation

@ebma

@ebma ebma commented Aug 4, 2026

Copy link
Copy Markdown
Member

Summary

  • replace static destination prefunding on every supported EVM chain with a versioned funding program derived from the validated presigned payout liability
  • fund only the destination native-balance shortfall; on same-chain flows, add the payout liability to the existing source reserve
  • include destination funding and payout execution in networkFeeUsd, converted from each chain's native token and protected by a configurable USD ceiling
  • persist absolute quote-time gas and fee ceilings so later deployments cannot change an accepted treasury liability
  • include Arbitrum parent-chain poster gas through NodeInterface and Base/Base Sepolia L1 security-fee upper bounds through GasPriceOracle
  • preflight the persisted envelope before provider registration, then recheck it before treasury funding
  • retain the historical static program for in-flight quotes without v2 metadata
  • preserve the typed NetworkFeesTooHigh 503 through quote, registration, and durable ramp error paths
  • retain the accepted fee-cap dust limitation without adding a sweep or smart-contract solution

Scope

The policy covers all configured EVM destinations: Ethereum, Arbitrum, Base, BSC, Avalanche, Moonbeam, Polygon, Base Sepolia, and Polygon Amoy. ETH-, POL/MATIC-, BNB-, AVAX-, and GLMR-denominated gas is converted to USD through the existing price feed.

Source-chain reserve constants remain static and continue to cover the upstream phase plan. For cross-chain payouts, the signed destination liability is funded separately. When source and destination are the same EVM network, the signed payout liability is added to the fixed source reserve so upstream phases cannot consume it. Exact provider-token direct payouts remain source-reserved because those topologies have no fee-distribution phase.

Funding and fee policy

Funding-program v2 persists:

  • the destination network and program version
  • absolute maximumFeePerGas
  • separate funding and payout gas limits
  • whether the payout is native or ERC-20
  • Base-family funding and payout L1-fee maxima

Arbitrum gas limits include the NodeInterface L1 poster-gas component plus the configured quote margin. Base-family pricing persists conservative getL1FeeUpperBound maxima; the payout reserve uses that accepted maximum and does not perform a late oracle call after bridge delivery.

Dynamic financial operations use v2 attempt classes and bind their request to the stable target balance rather than a live shortfall. This makes a confirmed funding send replayable after a balance-poll timeout or changed Base fee without repeating or permanently conflicting with the operation.

Quotes without globals.evmDestinationGas continue through the historical static-funding amounts and operation identities. This compatibility path remains until all such quotes and ramps have expired or completed.

Required rollout

EVM_DYNAMIC_DESTINATION_FUNDING_ENABLED defaults to false deliberately.

  1. Deploy this commit to every API and worker replica with EVM_DYNAMIC_DESTINATION_FUNDING_ENABLED=false. Those replicas can execute both legacy and v2 ramps, but still produce only legacy-compatible quotes.
  2. After every replica runs the dual executor, enable EVM_DYNAMIC_DESTINATION_FUNDING_ENABLED=true to start producing v2 quotes.

Do not enable v2 quote production during the first rolling deployment. The two-phase activation prevents an old worker from consuming new executor metadata and falling back to the old static treasury amounts.

Review note

#1311 is merged. This PR targets staging directly and includes the compatibility updates needed for staging's sequential EVM fee-distribution flow.

Verification

  • bun lint:fix
  • full workspace bun run typecheck
  • API build (650 files compiled)
  • full API suite: 1,100 passing, 40 intentionally skipped
  • focused funding, fee-policy, flow, idempotency, and corridor suites: 54 passing, 2 intentionally skipped
  • hermetic BRL-to-Arbitrum corridor covers dynamic shortfall funding through signed payout submission, legacy metadata compatibility, no-spend high-fee pause, durable error reason, typed 503 responses, and provider preflight ordering without transferring real tokens
  • read-only Arbitrum One NodeInterface calls verified the production ABI and parent-chain component for native and ERC-20 calldata; no transaction was submitted

@netlify

netlify Bot commented Aug 4, 2026

Copy link
Copy Markdown

Deploy Preview for vortex-sandbox ready!

Name Link
🔨 Latest commit 3eb8bae
🔍 Latest deploy log https://app.netlify.com/projects/vortex-sandbox/deploys/6a79df9467d557000800d81f
😎 Deploy Preview https://deploy-preview-1312--vortex-sandbox.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@ebma
ebma requested a balanced review from Copilot August 5, 2026 09:15

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.

🟡 Changes recommended

Same-chain reserve overlap, uncapped direct-flow funding, and incomplete Base Sepolia signing remain unresolved.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Makes EVM destination funding fee-aware across quoting, registration, signing, and execution.

Changes:

  • Prices destination gas and persists a registration-time fee envelope.
  • Funds only the signed payout liability shortfall.
  • Adds configuration, documentation, translations, and test coverage.
File summaries
File Description
packages/shared/src/helpers/signUnsigned.ts Centralizes the signing fee multiplier.
packages/shared/src/endpoints/quote.endpoints.ts Adds the high-network-fee error.
docs/security-spec/03-ramp-engine/ephemeral-accounts.md Documents dynamic destination funding.
apps/frontend/src/translations/pt.json Adds Portuguese error text.
apps/frontend/src/translations/en.json Adds English error text.
apps/frontend/src/stores/quote/useQuoteStore.ts Maps the new friendly error.
apps/api/src/tests/quote-pricing.golden.test.ts Updates fee-pricing goldens.
apps/api/src/tests/corridors/brl-onramp-crosschain.scenario.test.ts Expands destination pricing scenarios.
apps/api/src/test-utils/fake-world/fake-prices.ts Adds native-token test prices.
apps/api/src/constants/constants.ts Separates Moonbeam source reserves.
apps/api/src/config/vars.ts Adds destination gas configuration.
apps/api/src/config/vars.test.ts Tests configuration validation.
apps/api/src/api/services/phases/blocks/phases/subsidize-pre/simulation.ts Deducts destination network fees.
apps/api/src/api/services/phases/blocks/phases/fund-ephemeral/execution.ts Implements dynamic shortfall funding.
apps/api/src/api/services/phases/blocks/phases/final-settlement-subsidy/execution.ts Uses signed gas liability for native settlement.
apps/api/src/api/services/phases/blocks/phases/destination-transfer/transactions.ts Validates prepared fees against quotes.
apps/api/src/api/services/phases/blocks/core/types.ts Extends phase gas context.
apps/api/src/api/services/phases/blocks/core/metadata.ts Defines persisted fee envelopes.
apps/api/src/api/services/phases/blocks/core/flow.ts Controls and persists gas pricing.
apps/api/src/api/services/phases/blocks/core/fees.ts Includes destination execution costs.
apps/api/src/api/services/phases/blocks/core/evm-transactions.ts Defers fee multiplication to signing.
apps/api/src/api/services/phases/blocks/core/evm-destination-gas.ts Implements destination gas policy.
apps/api/src/api/services/phases/blocks/core/evm-destination-gas.test.ts Tests gas pricing and envelopes.
apps/api/src/api/services/phases/blocks/core/destination-funding.ts Replaces static funding amounts.
apps/api/src/api/services/phases/blocks/core/destination-funding.test.ts Tests liability and shortfalls.
apps/api/src/api/services/phases/blocks/__tests__/fund-ephemeral-user-hashes.test.ts Tests non-Ethereum funding liability.
apps/api/src/api/services/phases/blocks/__tests__/brl-onramp-base-same-chain.flow.test.ts Updates same-chain fixtures.
apps/api/src/api/services/phases/blocks/__tests__/brl-onramp-base-cross-chain.transactions.test.ts Verifies single fee multiplication.
apps/api/src/api/services/phases/blocks/__tests__/brl-onramp-base-cross-chain.flow.test.ts Updates cross-chain fixtures.
apps/api/src/api/services/phases/blocks/__tests__/alfredpay-onramp-direct.flow.test.ts Updates direct-flow fixtures.
apps/api/src/api/services/phases/blocks/__tests__/alfredpay-onramp-cross-chain.flow.test.ts Updates cross-chain fixtures.
apps/api/.env.example Documents gas-policy settings.
Review details
  • Files reviewed: 32/32 changed files
  • Comments generated: 3
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread apps/api/src/api/services/phases/blocks/phases/fund-ephemeral/execution.ts Outdated
Comment thread apps/api/src/api/services/phases/blocks/core/evm-destination-gas.ts
Base automatically changed from codex/enable-ethereum-onramps to staging August 7, 2026 16:50
@netlify

netlify Bot commented Aug 7, 2026

Copy link
Copy Markdown

Deploy Preview for vortexfi ready!

Name Link
🔨 Latest commit 3eb8bae
🔍 Latest deploy log https://app.netlify.com/projects/vortexfi/deploys/6a79df947d98c600089b822e
😎 Deploy Preview https://deploy-preview-1312--vortexfi.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Aug 7, 2026

Copy link
Copy Markdown

Deploy Preview for vrtx-dashboard canceled.

Name Link
🔨 Latest commit 3eb8bae
🔍 Latest deploy log https://app.netlify.com/projects/vrtx-dashboard/deploys/6a79df94fcf9a500081d116c

@ebma
ebma requested a balanced review from Copilot August 10, 2026 10:32

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 54 out of 54 changed files in this pull request and generated 2 comments.

Suppressed comments (1)

apps/api/src/api/services/phases/blocks/phases/fund-ephemeral/execution.ts:397

  • This preflight also executes before the destination v2 operation can replay a confirmed response. After a confirmed send followed by a balance-poll timeout, a still-lagging balance plus newly elevated gas/Base L1 fees pauses the ramp here even though no transaction needs to be sent again. Check the persisted operation first and only enforce the live envelope for a genuinely new broadcast.
      const fees = await destinationClient.estimateFeesPerGas();
      await assertEvmTreasuryFundingFeeWithinQuote(destinationGasQuote, destinationNetwork, fees.maxFeePerGas);

Comment thread apps/api/src/api/services/phases/blocks/phases/fund-ephemeral/execution.ts Outdated
Comment thread apps/api/src/api/services/phases/blocks/core/metadata.ts
@ebma
ebma requested a balanced review from Copilot August 10, 2026 13:35

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 56 out of 56 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

apps/api/src/config/vars.ts:114

  • Number accepts non-decimal JavaScript forms such as 0x10, so startup accepts that ceiling, but new Big(config.evmDestinationGas.maxExecutionFeeUsd) later rejects it and all dynamic quotes fail at runtime. Validate the stored string as decimal syntax here so invalid configuration fails during startup.
function readPositiveDecimalEnv(name: string, defaultValue: string): string {
  const rawValue = process.env[name] ?? defaultValue;
  const value = Number(rawValue.trim());
  if (!Number.isFinite(value) || value <= 0 || rawValue.trim() === "") {
    throw new Error(`${name} must be a positive number`);
  }
  return rawValue.trim();

Comment thread apps/api/src/api/services/phases/blocks/core/evm-destination-gas.ts Outdated
@ebma
ebma requested a balanced review from Copilot August 10, 2026 14:38

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 56 out of 56 changed files in this pull request and generated no new comments.

Suppressed comments (1)

apps/api/src/api/services/ramp/ramp.service.ts:944

  • The preflight trusts the network embedded in persisted JSON without binding it to the quote destination. If this envelope is malformed or manually edited to name another EVM chain, this check can pass on that chain, flow.register can create its durable provider ticket, and only the later destination-transfer preparation rejects the mismatch. Fail closed on the network mismatch here so no provider side effect occurs first.
    if (metadata.globals.evmDestinationGas) {
      // Run the same persisted-envelope guard before provider registration can
      // create an independently durable ticket. prepareTxs keeps its exact check.
      await preflightEvmDestinationFeeWithinQuote(metadata.globals.evmDestinationGas);

@ebma
ebma marked this pull request as ready for review August 10, 2026 15:32
@ebma
ebma merged commit ef01443 into staging Aug 10, 2026
8 checks passed
@ebma
ebma deleted the codex/dynamic-evm-destination-funding branch August 10, 2026 15:32
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