feat(stellar): implement Soroban pre-flight budget enforcement and DE…#862
Merged
temma02 merged 2 commits intoJun 27, 2026
Conversation
…X liquidity aggregation Closes StellerCraft#773 — Soroban Contract Execution Budget Enforcement with Pre-Flight Fee Estimation Closes StellerCraft#772 — Stellar DEX Liquidity Aggregation Service with Multi-Hop Route Optimization === Issue StellerCraft#773: Soroban Pre-Flight Budget Enforcement === Problem: Contract invocations in soroban.ts were being broadcast directly to the network without first simulating them. This meant there was no way to know ahead of time whether a call would exceed the configured CPU instruction or memory budget, and no fee estimation was performed before submission. Solution — packages/stellar/src/soroban-budget-monitor.ts: • Introduced BudgetLimits interface (maxCpuInstructions, maxMemoryBytes) with sensible Protocol-21 defaults (100M CPU instructions, 40 MB memory). • extractBudgetUsage() reads cost.cpuInsns and cost.memBytes from a successful SorobanRpc.Api.SimulateTransactionSuccessResponse. • checkBudget() compares actual usage against configured limits and returns a BudgetCheckResult that includes the estimated minimum resource fee (simResult.minResourceFee). Solution — packages/stellar/src/soroban.ts: • createRpcServer() creates a SorobanRpc.Server pointed at the configured SOROBAN_RPC_URL (defaults to soroban-testnet.stellar.org). • preflightTransaction() runs rpc.simulateTransaction() on the unsigned transaction, asserts the response is a success (not an error or restore), calls checkBudget() and throws a descriptive error if any limit is exceeded, then calls SorobanRpc.assembleTransaction() to stamp the correct resource fee footprint onto the transaction and returns the ready-to-sign tx together with the BudgetCheckResult. • invokeContract() composes the full lifecycle: preflight → sign → sendTransaction → poll getTransaction until NOT_FOUND resolves, throwing on FAILED status. • Both functions accept optional budgetLimits and rpc arguments so they can be tested with mocks or tightened per-call without changing global state. === Issue StellerCraft#772: DEX Liquidity Aggregation with Multi-Hop Route Optimization === Problem: dex-price-feed.ts only fetched spot prices from the DEX order book. There was no logic to discover optimal swap paths through the Stellar liquidity network, leaving users with sub-optimal execution on large or illiquid swaps. Solution — packages/stellar/src/dex-price-feed.ts: • findBestStrictSendRoutes(sourceAsset, sourceAmount, destinationAsset): Calls Horizon's strictSendPaths endpoint, which explores all available liquidity paths (AMM pools + order books) across up to MAX_HOPS (6) hops. Results are filtered to paths with ≤ 5 intermediate assets (path array excludes source and destination, so total hops ≤ 6), then sorted descending by destinationAmount — i.e. the route that gives the most output for your fixed input is first. • findBestStrictReceiveRoutes(sourceAsset, destinationAsset, destinationAmount): Mirror function using strictReceivePaths for fixed-output swaps. Sorted ascending by sourceAmount (cheapest source cost first). • getOptimalRoute(): Thin wrapper that returns the single best strict-send route or null if Horizon finds no path. • getPrice(): Retained from the original design — fetches the mid-market price from the order book (average of best ask and best bid). • assetFromRecord() helper converts Horizon path records (asset_type / asset_code / asset_issuer) to StellarSdk.Asset instances, handling the native XLM case. • All public functions accept an optional server argument for dependency injection / testing. === Supporting files === • packages/stellar/src/config.ts — exports STELLAR_NETWORK, HORIZON_URL, SOROBAN_RPC_URL from env with testnet defaults. • packages/stellar/src/service.ts — placeholder module (future Horizon helpers) • packages/stellar/src/mock.ts — placeholder module (future test mocks) • packages/stellar/src/index.ts — re-exports all new modules alongside the existing service/config/mock exports.
|
@whiteghost0001 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #773 — Soroban Contract Execution Budget Enforcement with Pre-Flight Fee Estimation Closes #772 — Stellar DEX Liquidity Aggregation Service with Multi-Hop Route Optimization
=== Issue #773: Soroban Pre-Flight Budget Enforcement ===
Solution — packages/stellar/src/soroban-budget-monitor.ts:
• Introduced BudgetLimits interface (maxCpuInstructions, maxMemoryBytes) with
sensible Protocol-21 defaults (100M CPU instructions, 40 MB memory).
• extractBudgetUsage() reads cost.cpuInsns and cost.memBytes from a successful
SorobanRpc.Api.SimulateTransactionSuccessResponse.
• checkBudget() compares actual usage against configured limits and returns a
BudgetCheckResult that includes the estimated minimum resource fee
(simResult.minResourceFee).
Solution — packages/stellar/src/soroban.ts:
• createRpcServer() creates a SorobanRpc.Server pointed at the configured
SOROBAN_RPC_URL (defaults to soroban-testnet.stellar.org).
• preflightTransaction() runs rpc.simulateTransaction() on the unsigned
transaction, asserts the response is a success (not an error or restore),
calls checkBudget() and throws a descriptive error if any limit is exceeded,
then calls SorobanRpc.assembleTransaction() to stamp the correct resource fee
footprint onto the transaction and returns the ready-to-sign tx together with
the BudgetCheckResult.
• invokeContract() composes the full lifecycle: preflight → sign → sendTransaction
→ poll getTransaction until NOT_FOUND resolves, throwing on FAILED status.
• Both functions accept optional budgetLimits and rpc arguments so they can be
tested with mocks or tightened per-call without changing global state.
=== Issue #772: DEX Liquidity Aggregation with Multi-Hop Route Optimization ===
Problem:
dex-price-feed.ts only fetched spot prices from the DEX order book. There was
no logic to discover optimal swap paths through the Stellar liquidity network,
leaving users with sub-optimal execution on large or illiquid swaps.
Solution — packages/stellar/src/dex-price-feed.ts:
• findBestStrictSendRoutes(sourceAsset, sourceAmount, destinationAsset):
Calls Horizon's strictSendPaths endpoint, which explores all available
liquidity paths (AMM pools + order books) across up to MAX_HOPS (6) hops.
Results are filtered to paths with ≤ 5 intermediate assets (path array
excludes source and destination, so total hops ≤ 6), then sorted descending
by destinationAmount — i.e. the route that gives the most output for your
fixed input is first.
• findBestStrictReceiveRoutes(sourceAsset, destinationAsset, destinationAmount):
Mirror function using strictReceivePaths for fixed-output swaps. Sorted
ascending by sourceAmount (cheapest source cost first).
• getOptimalRoute(): Thin wrapper that returns the single best strict-send route
or null if Horizon finds no path.
• getPrice(): Retained from the original design — fetches the mid-market price
from the order book (average of best ask and best bid).
• assetFromRecord() helper converts Horizon path records (asset_type /
asset_code / asset_issuer) to StellarSdk.Asset instances, handling the
native XLM case.
• All public functions accept an optional server argument for dependency
injection / testing.
=== Supporting files ===
• packages/stellar/src/config.ts — exports STELLAR_NETWORK, HORIZON_URL,
SOROBAN_RPC_URL from env with testnet
defaults.
• packages/stellar/src/service.ts — placeholder module (future Horizon helpers)
• packages/stellar/src/mock.ts — placeholder module (future test mocks)
• packages/stellar/src/index.ts — re-exports all new modules alongside the
existing service/config/mock exports.