fix: Fix issues with latest stellar-base version#101
Conversation
WalkthroughThe pull request fixes an issue with Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Plugin as Plugin<br/>(simulation.ts)
participant RPC as Stellar RPC
participant TB as TransactionBuilder
rect rgba(200, 100, 100, 0.5)
Note over Client,TB: Previous Flow (with rpc.assembleTransaction)
Client->>Plugin: buildWithChannel(tx)
Plugin->>RPC: simulateTransaction(tx)
RPC-->>Plugin: simResult (resourceFee, auth, transactionData)
Plugin->>RPC: assembleTransaction(simResult)
RPC-->>Plugin: assembled tx
Plugin-->>Client: transaction
end
rect rgba(100, 150, 200, 0.5)
Note over Client,TB: New Flow (with direct TransactionBuilder)
Client->>Plugin: buildWithChannel(tx)
Plugin->>RPC: simulateTransaction(tx)
RPC-->>Plugin: simResult (resourceFee, auth, sorobanData)
Plugin->>Plugin: parse sorobanData & resolve auth
Plugin->>TB: new TransactionBuilder with sorobanData
TB-->>Plugin: built transaction
Plugin-->>Client: transaction
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
This PR updates Soroban transaction assembly and fee calculation to avoid double-counting resourceFee introduced by recent @stellar/stellar-sdk changes, and adds regression tests to lock in correct fee behavior.
Changes:
- Build channel-sourced transactions directly from
simulation.transactionDatainstead ofrpc.assembleTransaction()to prevent double-addingresourceFee. - Add a safety floor in max-fee calculation so fee-bump
max_feenever underpays the inner transaction fee. - Extend tests to cover “resource fee added exactly once” and “inner tx fee as floor” scenarios.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
src/plugin/simulation.ts |
Switches away from assembleTransaction() and constructs the tx with simulation-derived SorobanTransactionData to avoid double resource-fee addition. |
src/plugin/fee.ts |
Ensures computed fee-bump max_fee is at least the inner transaction fee (plus inclusion fee) when mismatches occur. |
test/read-only.test.ts |
Adds a regression test ensuring inner tx fee equals classic fee + resource fee exactly once. |
test/fee.test.ts |
Adds a test ensuring calculateMaxFee floors to the inner tx fee when computed fee would underpay. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/plugin/simulation.ts (1)
150-152:⚠️ Potential issue | 🟠 MajorAuth expiry validation is skipped for simulation-derived auth.
At Line 151 you validate only the input
auth, but at Lines 170-175 you may replace it with auth decoded fromsimResult. That fallback path bypassesvalidateAuthExpiry, so near-expiry signatures can slip through and fail downstream.Suggested fix
- if (simResult.latestLedger) { - validateAuthExpiry(auth, simResult.latestLedger, minSignatureExpirationLedgerBuffer); - } + const resolvedAuth = + auth && auth.length > 0 + ? auth + : (simResult.results?.[0]?.auth ?? []).map((a: string) => + xdr.SorobanAuthorizationEntry.fromXDR(a, 'base64') + ); + + if (simResult.latestLedger !== undefined) { + validateAuthExpiry(resolvedAuth, simResult.latestLedger, minSignatureExpirationLedgerBuffer); + } @@ - const resolvedAuth = - auth && auth.length > 0 - ? auth - : (simResult.results?.[0]?.auth ?? []).map((a: string) => - xdr.SorobanAuthorizationEntry.fromXDR(a, 'base64') - );Also applies to: 169-175
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/plugin/simulation.ts` around lines 150 - 152, The current code validates only the original auth variable (validateAuthExpiry(auth, simResult.latestLedger, minSignatureExpirationLedgerBuffer)) but later may replace auth with the simulation-decoded auth from simResult, so the fallback path skips expiry validation; update the flow to validate the effective auth after any replacement: after you set or decode auth from simResult (referencing simResult and the variable auth/decoded auth), call validateAuthExpiry(effectiveAuth, simResult.latestLedger, minSignatureExpirationLedgerBuffer) so the auth used downstream is always checked against simResult.latestLedger and minSignatureExpirationLedgerBuffer.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/plugin/simulation.ts`:
- Around line 167-174: Several parsing/assembly calls
(xdr.SorobanTransactionData.fromXDR when creating sorobanData,
xdr.SorobanAuthorizationEntry.fromXDR when building resolvedAuth, and the
TransactionBuilder(...).build() sequence) are running outside a try/catch so
decoding errors escape instead of returning a pluginError with code
ASSEMBLY_FAILED; wrap the entire assembly/parsing block that produces
sorobanData, resolvedAuth and the TransactionBuilder(...).build() call in a
try/catch, catch any exception, normalize it into the plugin error envelope with
code "ASSEMBLY_FAILED" and a clear message, and return/throw that pluginError
instead of letting raw exceptions propagate.
---
Outside diff comments:
In `@src/plugin/simulation.ts`:
- Around line 150-152: The current code validates only the original auth
variable (validateAuthExpiry(auth, simResult.latestLedger,
minSignatureExpirationLedgerBuffer)) but later may replace auth with the
simulation-decoded auth from simResult, so the fallback path skips expiry
validation; update the flow to validate the effective auth after any
replacement: after you set or decode auth from simResult (referencing simResult
and the variable auth/decoded auth), call validateAuthExpiry(effectiveAuth,
simResult.latestLedger, minSignatureExpirationLedgerBuffer) so the auth used
downstream is always checked against simResult.latestLedger and
minSignatureExpirationLedgerBuffer.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
.changeset/humble-ducks-sin.mdsrc/plugin/fee.tssrc/plugin/simulation.tstest/fee.test.tstest/read-only.test.ts
This PR will fix issues with latest stellar-base version.
In the latest version TransactionBuilder.build() now includes resourceFee.
Our logic used assembleTransaction and with latest change it resulted in double addition of resourceFee.
stellar/js-stellar-base#861
Summary by CodeRabbit
Bug Fixes
Tests